Steven Ickman 的解决方案很方便,但不完整。Danny Becket 和 Sam 的答案更短且更手动,并且在具有同时需要动态和词法范围“this”的回调的相同一般情况下失败。如果我在下面的解释是 TL;DR,请跳到我的代码...
我需要为动态范围保留“this”以与库回调一起使用,并且我需要一个“this”与类实例的词法范围。我认为将实例传递给回调生成器是最优雅的,有效地让参数关闭类实例。如果您错过了这样做,编译器会告诉您。我使用调用词法范围参数“outerThis”的约定,但“self”或其他名称可能更好。
“this”关键字的使用是从 OO 世界中偷来的,当 TypeScript 采用它时(我推测来自 ECMAScript 6 规范),每当一个方法被不同的实体调用时,他们将词法范围的概念和动态范围的概念混为一谈. 我对此有点恼火;我更喜欢 TypeScript 中的“self”关键字,这样我就可以将词法范围的对象实例从它上面移开。或者,可以将 JS 重新定义为在需要时需要显式的第一位置“调用者”参数(从而一举破坏所有网页)。
这是我的解决方案(从大班中摘录)。特别看一下方法的调用方式,尤其是“dragmoveLambda”的主体:
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;
}
}
}