从打字稿中的超类调用重写的方法


75

当我从超类构造函数中调用重写的方法时,我无法正确获取子类属性的值。

class A
{
    constructor()
    {
        this.MyvirtualMethod();
    }

    protected MyvirtualMethod(): void
    {

    }
}

class B extends A
{
    private testString: string = "Test String";

    public MyvirtualMethod(): void
    {
        alert(this.testString); // This becomes undefined
    }
}

我想知道如何正确覆盖打字稿中的函数。


14
在任何OOP语言中,在构造函数中调用虚拟方法都被认为是不好的做法:google.com/search?
q=

1
我几乎错过了下面的@Flavien Volken答案,这仅是因为它不是“已接受”的答案(从投票中看起来应该是这样)才帮助我解决了这个问题。请考虑将其更改以供其他人使用...
benshabatnoam

Answers:


20

执行顺序为:

  1. A的构造函数
  2. B的构造函数

分配发生在B的构造函数之后,在A的构造函数中_super被调用了-被称为:

function B() {
    _super.apply(this, arguments);   // MyvirtualMethod called in here
    this.testString = "Test String"; // testString assigned here
}

因此发生以下情况:

var b = new B();     // undefined
b.MyvirtualMethod(); // "Test String"

您将需要更改代码以解决此问题。例如,通过调用this.MyvirtualMethod()inB的构造函数,通过创建一个工厂方法来创建对象然后执行该函数,或者将字符串传递到A的构造函数中并以某种方式进行处理,这存在很多可能性。


我们不是在这里new.target有用的情况下吗?
GameAlchemist

1
我们在谈论打字稿吗?
Long Field

128

关键是使用super.methodName()调用父方法。

class A {
    // A protected method
    protected doStuff()
    {
        alert("Called from A");
    }

    // Expose the protected method as a public function
    public callDoStuff()
    {
        this.doStuff();
    }
}

class B extends A {

    // Override the protected method
    protected doStuff()
    {
        // If we want we can still explicitly call the initial method
        super.doStuff();
        alert("Called from B");
    }
}

var a = new A();
a.callDoStuff(); // Will only alert "Called from A"

var b = new B()
b.callDoStuff(); // Will alert "Called from A" then "Called from B"

在这里尝试


3
绝对应该是“已接受”的答案(几乎没有,因为它不是)。谢谢。
benshabatnoam

16

如果要让超类从子类中调用函数,最干净的方法是定义一个抽象模式,以这种方式,您明确地知道该方法存在于某处,并且必须被子类覆盖。

这是一个示例,通常您不会在构造函数内调用子方法,因为该子实例尚未初始化……(原因为何您的问题示例中存在“未定义”)

abstract class A {
    // The abstract method the subclass will have to call
    protected abstract doStuff():void;

    constructor(){
     alert("Super class A constructed, calling now 'doStuff'")
     this.doStuff();
    }
}

class B extends A{

    // Define here the abstract method
    protected doStuff()
    {
        alert("Submethod called");
    }
}

var b = new B();

在这里测试

如果像@Max这样,您真的想避免在任何地方实现抽象方法,那就摆脱它。我不推荐这种方法,因为您可能会忘记自己正在覆盖该方法。

abstract class A {
    constructor() {
        alert("Super class A constructed, calling now 'doStuff'")
        this.doStuff();
    }

    // The fallback method the subclass will call if not overridden
    protected doStuff(): void {
        alert("Default doStuff");
    };
}

class B extends A {
    // Override doStuff()
    protected doStuff() {
        alert("Submethod called");
    }
}

class C extends A {
    // No doStuff() overriding, fallback on A.doStuff()
}

var b = new B();
var c = new C();

在这里尝试


2
即使不需要该解决方案,您也将在每个子类中强制定义此方法。
Max

3
@Max是摘要的唯一目的。我把一个例子,我的回答对您
Flavien Volken

0

以下是一个通用示例

    //base class
    class A {
        
        // The virtual method
        protected virtualStuff1?():void;
    
        public Stuff2(){
            //Calling overridden child method by parent if implemented
            this.virtualStuff1 && this.virtualStuff1();
            alert("Baseclass Stuff2");
        }
    }
    
    //class B implementing virtual method
    class B extends A{
        
        // overriding virtual method
        public virtualStuff1()
        {
            alert("Class B virtualStuff1");
        }
    }
    
    //Class C not implementing virtual method
    class C extends A{
     
    }
    
    var b1 = new B();
    var c1= new C();
    b1.Stuff2();
    b1.virtualStuff1();
    c1.Stuff2();
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.