Typescript 在super()调用中访问它

Typescript 在super()调用中访问它,typescript,Typescript,在上面的代码中,我需要某种方式将updateNode函数传递到超级调用。编译器对此表示不满,并指出: 关键字“this”不能在类主体的初始值设定项中引用,也不能在超级构造函数调用中引用 有什么办法可以解决这个问题吗?这里的用例是,我已经将大量与列表遍历相关的锅炉板代码抽象到这个基类中,这个基类由几个执行实际工作的特定系统扩展。基类需要方法来调用update、add和remove…为什么不重写这样的方法: class MySystem extends ListIteratingSystem {

在上面的代码中,我需要某种方式将updateNode函数传递到超级调用。编译器对此表示不满,并指出:

关键字“this”不能在类主体的初始值设定项中引用,也不能在超级构造函数调用中引用


有什么办法可以解决这个问题吗?这里的用例是,我已经将大量与列表遍历相关的锅炉板代码抽象到这个基类中,这个基类由几个执行实际工作的特定系统扩展。基类需要方法来调用update、add和remove…

为什么不重写这样的方法:

class MySystem extends ListIteratingSystem {
    constructor (private creator: EntityCreator) {
        super(MyNode, this.updateNode);
    }

    updateNode() {/* sniiiiip */}

    /* sniiiip */
}
执行
newmysystem().execute()显示警报


不幸的是,现在还没有好的方法来制作
executeOnStart
方法
protectedabstract
。这有点违反直觉,但请记住可见性访问器仅用于编译器和智能化。

我对用例的语义不是100%清楚,但根据目标,您有一些选项

首先将
updateNode
/
addNode
/
removeNode
定义为基类的成员,并让派生类覆盖它们(而不是将它们指定为构造函数参数)。这对于派生的实现来说不太清楚,因为TypeScript没有“抽象”的概念,但可能是最干净、最简单的

第二种方法是重构一点,让派生类提供一个类型参数,而不是方法列表,并将更新/添加/删除函数放在“姐妹”类中,这些类以一种方式提供该功能,让基类为它们提供所需的上下文,否则您将从
中获得该
。这是更多的工作,但却是更好的分离关注点。如果您试图实现控制模式的反转,那么最好通过组合而不是继承来实现

最后一个选项是将整个类层次结构颠倒过来,并将遍历/etc代码移动到单独的类中,这些单独的实现将使用该类,本质上是反反转现有代码中的任何控制反转


我应该补充一点,在基类构造函数参数位置不引用
this
的限制通常是一个很好的限制——试图违反它通常意味着你正在为将来的失败做准备。在这种情况下,如果限制不到位,那么当您试图从
MySystem
继承时,或者当
ListIteratingSystem
决定在构建过程中调用
updateNode
时,您可能会遇到大麻烦。C#中的FxCop出于同样的原因强制执行此限制。

从TypeScript 1.3开始,您可以使用受保护的关键字和后期绑定,因此不必将方法传递给超类

仍然没有
abstract
关键字,因此您必须在基类中提供默认行为或抛出异常-但是
protected
关键字允许您覆盖基类实现(在当前版本的TypeScript中,private关键字不允许这样做)


感谢您的详细回复,我有足够的信息来做出明智的决定。回答一如既往地好。:)感谢代码示例,这是Ryan提到的第一个用例的良好演示。好东西,先生!请注意,使用此技术有一个缺点。如果派生类中有任何属性是在超级调用之前用初始值设定项初始化的,而不是在构造函数中,并且如果定义的方法使用这些成员中的任何一个,那么你的应用程序很可能会崩溃,因为当超级构造函数调用你的方法时,这些成员还没有初始化。@ZoltánTamási如果在基本构造函数中调用
executeOnStart
,你所说的将是正确的。在代码中,它不是。从基构造函数调用虚/抽象方法在任何语言中都是一种糟糕的做法,原因正是您所担心的。@Rafal啊,对不起,我误读了代码中的“execute”一词,它的长度与“constructor”一词的长度相似。你当然是对的,谢谢。
class ListIteratingSystem {
    execute() {
        this.executeOnStart();
    };

    private executeOnStart() {
       throw new Error('This method is abstract');
    };
};

class MySystem extends ListIteratingSystem {
    constructor (/*...*/) {
        super();
    }

   private executeOnStart() {
       alert("derived");
    };
}
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();