【问题标题】:Why does setting properties on ES6 classes not work when calling an overloaded function in the constructor of the parent为什么在父类的构造函数中调用重载函数时,在 ES6 类上设置属性不起作用
【发布时间】:2021-11-15 08:42:15
【问题描述】:

我在编写代码时遇到了这种情况,我无法理解。

场景如下:我有一个来自我正在扩展的库的类。 这个类是“父”类。它允许它的子类覆盖 init 方法以进行自定义初始化。

然而,第二个子类的行为并不像我预期的那样。两个类之间的唯一区别是成员变量的声明(?)。在编写纯 JS 时,我什至不会考虑这样做,但我正在用 Typescript 编写,这是编译后的结果(实际上,在我的特定情况下,我什至没有分配值。TS 编译器只包含一个“成员; " 并且输出显示为 "未定义)

我很确定这个问题只发生在当变量设置在由父构造函数调用的覆盖函数中时。

有人可以向我解释为什么会这样吗?

class Parent {
    constructor(initArgs) {
        this.init(initArgs);
    }

    init() {}
}

class ChildTest1 extends Parent {
    init(args) {
        this.member = args;
    }

    test() {
        console.log(`Member of ChildTest1 has value of "${this.member}"`);
    }
}

class ChildTest2 extends Parent {
    member = "default";

    init(args) {
        this.member = args;
    }

    test() {
        console.log(`Member of ChildTest2 has value of "${this.member}"`);
    }
}

new ChildTest1("Hello World").test();
new ChildTest2("Hello World").test();

输出以下内容:

ChildTest1 的成员的值为“Hello World”

ChildTest2 成员的值为“default”

【问题讨论】:

    标签: javascript typescript es6-class


    【解决方案1】:

    您的变量在初始化期间被覆盖。属性初始化和构造函数执行顺序如下:

    1. 你的父类的构造函数执行并将member初始化为Hello World

    2. 你的子类属性被初始化,覆盖之前初始化的成员变量。

    3. 您的子类构造函数执行

    我已经使您的代码更加明确(注意添加子构造函数在功能上等同于您的示例)来证明这一点:

    class Parent {
        constructor(initArgs) {
            this.init(initArgs);
            console.log(`Parent Constructor: Member of ChildTest2 has value of "${this.member}"`);
        }
    
        init() {}
    }
    
    class ChildTest2 extends Parent {
        member = "default";
    
        constructor(initArgs) {
            super(initArgs);
            console.log(`Child Constructor: Member of ChildTest2 has value of "${this.member}"`);
        }
    
        init(args) {
            this.member = args;
            console.log(`Init: Member of ChildTest2 has value of "${this.member}"`);
        }
    
        test() {
            console.log(`Test: Member of ChildTest2 has value of "${this.member}"`);
        }
    }
    
    new ChildTest2("Hello World").test();
    

    打印出来:

    [LOG]: "Init: Member of ChildTest2 has value of "Hello World"" 
    [LOG]: "Parent Constructor: Member of ChildTest2 has value of "Hello World"" 
    [LOG]: "Child Constructor: Member of ChildTest2 has value of "default"" 
    [LOG]: "Test: Member of ChildTest2 has value of "default""
    

    作为一种心理模型,您可以假设类属性初始化发生在构造函数内的super(...) 调用之后。更多关于here

    【讨论】:

    • 谢谢,这基本上是我在写完问题后想出的。在我的实际代码中,我什至没有为成员赋值。但我的打字稿代码“私人成员?:字符串;”只是编译成“member;”,但我想这相当于“member = undefined;”我只是使用该行进行类型检查,但我发现我可以使用“私有声明成员:字符串”,然后它就可以工作,因为声明不会编译为任何东西。
    猜你喜欢
    • 2011-07-06
    • 2015-04-24
    • 1970-01-01
    • 2017-11-10
    • 2016-03-29
    • 2018-02-28
    • 1970-01-01
    • 1970-01-01
    • 2011-09-07
    相关资源
    最近更新 更多