Steven Ickman løsning er hendig, men ufullstendig. Danny Becket og Sams svarene er kortere og mer manuell, og mislykkes i samme generelle tilfellet av å ha en tilbakeringing som trenger både dynamisk og leksikalsk scoped "dette" på samme tid. Hopp til min kode hvis min forklaring nedenfor er TL; DR ...
Jeg trenger å bevare "dette" for dynamisk scoping for bruk med bibliotektilbakeanrop, og jeg må ha en "dette" med leksikalsk scoping til klassen forekomst. Jeg mener at det er mest elegante å passere forekomsten inn i en tilbakeringings generator, effektivt slik at parameteren lukke over klasse forekomst. Kompilatoren forteller deg om du ikke rakk å gjøre det. Jeg bruker en konvensjon for å kalle de leksikalsk scoped parameter "outerThis", men "selv" eller et annet navn kan bli bedre.
Bruken av "dette" søkeord er stjålet fra OO verden, og når Loggfila adoptert det (fra ECMAScript 6 specs jeg antar), de smeltet sammen en leksikalsk scoped konsept og en dynamisk scoped konsept, når en metode kalles av en annen enhet . Jeg er litt fornærmet på dette; Jeg foretrekker en "self" søkeord i typescript, slik at jeg kan levere den leksikalske omfangs objekt eksempel ut av det. Alternativt JS kan bli omdefinert til å kreve en eksplisitt første-posisjon "som ringer" parameter når det er nødvendig (og dermed bryte alle websider i ett slag).
Her er min løsning (fjernet fra en stor klasse). Ta en titt spesielt på hvordan metodene er kalt, og kroppen av "dragmoveLambda" spesielt:
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;
}
}
}