Steven Ickman的解决方案很方便,但是不完整。Danny Becket和Sam的答案更短,更手动,并且在需要同时具有动态和词法作用域“this”的回调的同一常规情况下失败。如果我的下面的解释过长,请跳到我的代码...
我需要保留“this”以用于库回调的动态作用域,并且我需要具有与类实例相关的词法作用域“this”。我认为将实例传递给回调生成器最为优雅,从而使参数闭合类实例。编译器会告诉你是否漏掉了这样做。我使用将词法作用域参数称为“outerThis”的约定,但“self”或其他名称可能更好。
“this”关键字的使用被借用自OO世界,当TypeScript采用它时(我认为是从ECMAScript 6规范中采用的),它们混淆了一个词法作用域概念和一个动态作用域概念,每当方法由不同实体调用时。我对此有点恼火;我更喜欢在TypeScript中使用“self”关键字,以便我可以将词法作用域对象实例交给它。或者,JS可以被重新定义为在需要时需要明确的第一个位置的“caller”参数(从而一举打破所有网页)。
这是我的解决方案(从一个大类中删除)。特别注意方法的调用方式,以及“dragmoveLambda”的主体:
export class OntologyMappingOverview {
initGraph(){
...
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;
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;
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;
}
}
}