【问题标题】:Call an overridden method in base class constructor in typescript在打字稿的基类构造函数中调用重写的方法
【发布时间】:2015-08-29 10:38:09
【问题描述】:

当我从基类构造函数调用被覆盖的方法时,我无法正确获取子类属性的值。

例子:

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
    }
}

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

【问题讨论】:

  • 在构造函数中调用虚方法在任何 OOP 语言中都被认为是一种不好的做法:google.com/search?q=virtual+method+in+constructor
  • 我几乎错过了下面的@Flavien Volken answer,它帮助我解决了这个问题,只是因为它不是“接受”的答案(从投票看来应该是这样)。请考虑更改它以供其他人使用...
  • @benshabatnoam 该答案仅回答了问题的标题,考虑到正文中的问题,这是不正确的,因此我更新了问题的标题以匹配所问的内容。跨度>

标签: oop typescript typescript1.4


【解决方案1】:

下面是一个通用示例

    //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();

【讨论】:

    【解决方案2】:

    关键是使用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"
    

    Try it here

    【讨论】:

    • 绝对应该是“接受”的答案(几乎错过了它,因为它不是)。谢谢。
    • @benshabatnoam 问题是关于如何在基类的构造函数中调用它,这个答案没有回答。
    【解决方案3】:

    如果您希望超类从子类调用函数,最简洁的方法是定义抽象模式,这样您就可以明确知道该方法存在于某处并且必须被子类覆盖。

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

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

    测试一下Here

    如果你真的想避免在任何地方实现抽象方法,就像 @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();
    

    试试Here

    【讨论】:

    • 此解决方案将强制在每个子类中定义此方法,即使不需要。
    • @Max 这是摘要的唯一目的。我在给你的答案中举了一个例子
    【解决方案4】:

    执行顺序为:

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

    A 的构造函数——_super——被调用之后,赋值发生在B 的构造函数中:

    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"
    

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

    【讨论】:

    • 我们不是在 new.target 可能有用的情况下吗?
    • 我们在谈论 Typescript 吗?
    • @LongField 是的。它显示了 B 类的已编译 ES5 JavaScript,以显示执行顺序。
    猜你喜欢
    • 1970-01-01
    • 2017-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-15
    • 1970-01-01
    • 2020-07-28
    • 2017-01-29
    相关资源
    最近更新 更多