Steven Ickman Řešení je po ruce, ale neúplná. Danny Becket a odpovědi Samovy jsou kratší a více manuální a selhání ve stejném obecném případě, že bude zpětné volání, že potřebuje oba dynamický a lexically scoped „toto“ ve stejnou dobu. Přeskočit na můj kód, pokud níže moje vysvětlení je TL; DR ...
Musím zachovat „to“ dynamické scoping pro použití knihovny zpětné volání, a musím mít „to“ s lexikální scoping na instanci třídy. Tvrdím, že je nejelegantnější předat případ do generátoru zpětné volání, efektivně nechat uzavření parametru přes instanci třídy. Kompilátor vám řekne, jestli jste vynechal tom. I používat konvenci volání lexically rozsahem parametr „outerThis“, ale „já“ nebo jiný název by mohl být lepší.
Použití „této“ klíčové slovo je ukraden z OO světě, a když ji na psacím stroji přijato (od ECMAScript 6 specifikace já předpokládám), že se sjednotil se lexically scoped koncepci a dynamicky scoped koncept, kdykoli je metoda nazývá jiným subjektem , Jsem trochu naštvaný na to; Dal bych přednost „self“ klíčové slovo na psacím stroji, takže mohu předat instanci lexically scoped objekt mimo něj. Střídavě, JS, kterou lze předefinovat vyžadovat parametr explicitní první poloha „volajícím“, když je to potřeba (a tím porušit všechny webové stránky v naráz).
Tady je moje řešení (vystřižen z velké třídy). Mrkněte zejména nad tím, jak se nazývají metody a tělo „dragmoveLambda“ zejména:
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;
}
}
}