class MySystem extends ListIteratingSystem {
constructor (private creator: EntityCreator) {
super(MyNode, this.updateNode);
}
updateNode() {/* sniiiiip */}
/* sniiiip */
}
在上面的代码中,我需要一些方法将updateNode函数传递给super调用。编译器抱怨说:
Keyword 'this' cannot be referenced in initializers in a class body, or in super constructor calls
关于如何解决这个问题的任何想法?这里的用例是我抽取了很多与列表遍历相关的锅炉板代码,并将其抽象到这个基类中,该基类由几个完成实际工作的特定系统扩展。基类需要调用更新,添加和删除的方法......
答案 0 :(得分:5)
我不是100%清楚你的用例的语义,但你有一些选择取决于目标。
首先,只需将updateNode
/ addNode
/ removeNode
定义为基类的成员,然后让派生类覆盖它们(而不是将它们指定为构造函数参数)。这对于你的派生实现来说有点不太清楚,因为TypeScript没有'abstract'的概念,但可能是最干净和最简单的。
第二种方法是重构一下,让派生类提供类型参数而不是方法列表,并将update / add / remove函数放在提供该类的“姐妹”类中功能以一种方式让基类为他们提供您从this
获得的所需上下文。这是更多的工作,但更好地分离关注点。如果你试图完成控制模式的反转,那么最好通过组合而不是继承来完成。
最后一个选项是将整个类层次结构颠倒过来,并将遍历/ etc代码移动到这些单独实现将使用的单独类中,基本上反转现有代码中的任何控制反转。
我应该补充一点,你没有在基类构造函数参数位置引用this
的限制通常是一个非常好的限制 - 试图违反它通常意味着你正在为自己的失败做好准备。在这种情况下,如果没有限制,当您尝试从MySystem
继承时,或者ListIteratingSystem
决定应该调用updateNode
时,您可能会遇到大麻烦在施工期间的某个时间。 C#中的FxCop也出于同样的原因强制执行此限制。
答案 1 :(得分:3)
为什么不重写这样的方法:
class ListIteratingSystem {
execute() {
this.executeOnStart();
};
private executeOnStart() {
throw new Error('This method is abstract');
};
};
class MySystem extends ListIteratingSystem {
constructor (/*...*/) {
super();
}
private executeOnStart() {
alert("derived");
};
}
执行new MySystem().execute();
会显示警告。
不幸的是,还没有很好的方法来制作executeOnStart
方法protected abstract
。这有点违反直觉,但请记住,可见性访问器仅适用于编译器和智能。
答案 2 :(得分:3)
从TypeScript 1.3开始,您可以使用protected关键字和后期绑定,因此您不必将该方法传递给超类。
仍然没有abstract
关键字,因此您必须提供默认行为或在基类中抛出异常 - 但protected
关键字允许您覆盖基类实现( private关键字在当前版本的TypeScript中不允许这样做。
class ListIteratingSystem {
doSomething() {
this.updateNode();
}
protected updateNode() {
alert('Super');
}
}
class MySystem extends ListIteratingSystem {
protected updateNode() {
alert('Sub');
}
}
var a = new ListIteratingSystem();
a.doSomething();
var b = new MySystem();
b.doSomething();