La soluzione di Steven Ickman è a portata di mano, ma incompleta. Danny Becket e le risposte di Sam sono più brevi e più manuali, e non riescono nello stesso caso generale di avere un callback che ha bisogno sia dinamico e con scope lessicale "questo" allo stesso tempo. Passa al mio codice, se la mia spiegazione che segue è TL; DR ...
Ho bisogno di conservare "questo" per scoping dinamico per l'utilizzo con i callback biblioteca, e ho bisogno di avere un "presente" con scoping lessicale per l'istanza della classe. Io sostengo che è più elegante di passare l'istanza in un generatore di callback, lasciando che in modo efficace la chiusura dei parametri sopra l'istanza di classe. Il compilatore ti dice se vi siete persi farlo. Io uso una convenzione di chiamare il parametro "outerThis" scope lessicale, ma "io" o un altro nome potrebbe essere migliore.
L'uso del "questo" parola chiave è stato rubato dal mondo OO, e quando dattiloscritto ha adottato (da ECMAScript 6 spec presumo), hanno conflated un concetto con scope lessicale e di un concetto ambito in modo dinamico, ogni volta che un metodo viene chiamato da un soggetto diverso . Sono un po 'seccata a questo; Io preferirei una parola chiave "sé" a macchina in modo che possa consegnare l'istanza di oggetto con scope lessicale fuori di esso. In alternativa, JS potrebbe essere ridefinito per richiedere una prima posizione di parametro "chiamante" esplicito quando è necessario (e quindi rompere tutte le pagine web in un colpo solo).
Ecco la mia soluzione (asportato da una vasta classe). Date un'occhiata in particolare il modo in cui i metodi vengono chiamati, e il corpo di "dragmoveLambda", in particolare:
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;
}
}
}