在super()调用中访问它

时间:2012-11-30 06:26:45

标签: typescript

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

关于如何解决这个问题的任何想法?这里的用例是我抽取了很多与列表遍历相关的锅炉板代码,并将其抽象到这个基类中,该基类由几个完成实际工作的特定系统扩展。基类需要调用更新,添加和删除的方法......

3 个答案:

答案 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();