La solution de Steven Ickman est à portée de main, mais incomplète. Danny Becket et les réponses de Sam sont plus courtes et plus manuel, et ne parviennent pas dans le même cas général d'avoir un rappel qui a besoin à la fois dynamique et lexicalement scope « ce » en même temps. Passer à mon code si mon explication ci-dessous est TL; DR ...
Je dois préserver « cette » pour la portée dynamique pour une utilisation avec callbacks bibliothèque, et je dois avoir un « ce » avec une portée lexicale à l'instance de classe. Je soutiens qu'il est le plus élégant de passer l'instance dans un générateur de rappel, laissant effectivement la fermeture des paramètres sur l'instance de classe. Le compilateur vous indique si vous avez manqué le faire. J'utilise une convention d'appeler le paramètre « scope outerThis lexicalement », mais « moi » ou un autre nom peut - être mieux.
L'utilisation du « ce » mot-clé est volé dans le monde OO, et quand tapuscrit a adopté (à partir ECMAScript 6 spécifications Je présume), ils confondait un concept lexicalement scope et un concept dynamique scope, chaque fois qu'une méthode est appelée par une autre entité . Je suis un peu vexé à ce; Je préférerais un mot-clé « auto » en caractères d'imprimerie afin que je puisse remettre l'instance d'objet scope lexicalement hors de lui. Alternativement, JS pourrait être redéfinie comme exigeant une première position de paramètre « appelant » quand il est nécessaire (et donc briser toutes les pages Web d'un seul coup).
Voici ma solution (excisé une grande classe). Prenez un coup d'oeil en particulier la façon dont les méthodes sont appelées, et le corps de « dragmoveLambda » en particulier:
export class OntologyMappingOverview {
initGraph(){
...
// Using D3, have to provide a container of mouse-drag behavior functions
// to a force layout graph
this.nodeDragBehavior = d3.behavior.drag()
.on("dragstart", this.dragstartLambda(this))
.on("drag", this.dragmoveLambda(this))
.on("dragend", this.dragendLambda(this));
...
}
dragmoveLambda(outerThis: OntologyMappingOverview): {(d: any, i: number): void} {
console.log("redefine this for dragmove");
return function(d, i){
console.log("dragmove");
d.px += d3.event.dx;
d.py += d3.event.dy;
d.x += d3.event.dx;
d.y += d3.event.dy;
// Referring to "this" in dynamic scoping context
d3.select(this).attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
outerThis.vis.selectAll("line")
.filter(function(e, i){ return e.source == d || e.target == d; })
.attr("x1", function(e) { return e.source.x; })
.attr("y1", function(e) { return e.source.y; })
.attr("x2", function(e) { return e.target.x; })
.attr("y2", function(e) { return e.target.y; });
}
}
dragging: boolean =false;
// *Call* these callback Lambda methods rather than passing directly to the callback caller.
dragstartLambda(outerThis: OntologyMappingOverview): {(d: any, i: number): void} {
console.log("redefine this for dragstart");
return function(d, i) {
console.log("dragstart");
outerThis.dragging = true;
outerThis.forceLayout.stop();
}
}
dragendLambda(outerThis: OntologyMappingOverview): {(d: any, i: number): void} {
console.log("redefine this for dragend");
return function(d, i) {
console.log("dragend");
outerThis.dragging = false;
d.fixed = true;
}
}
}