首页 > 解决方案 > 子类中的字段初始化发生在构造函数在父类中完成之后,在 javascript 中。这是设计使然吗?

问题描述

展示比描述更容易。这是代码

let ns = {};

ns.A = class {
    constructor() { 
        this.Virtual();
    }   

    Virtual() {
    }
};

ns.B = class extends ns.A {
    constructor() {
        super();
        alert(this.Field);
    }

    Field = 0;  

    Virtual() {
        this.Field = 123;
    }
}

alert()表示等于 0。即 B 类中的this.Field字段初始化是在 A 构造函数完成后执行的。这是Javascript中的“设计”吗?

如果我把它放在FieldB 类的原型中,那么一切正常,就像在任何其他语言中一样。例如

let ns = {};

ns.A = class {
    constructor() { 
        this.Virtual();
    }   

    Virtual() {
    }
};

ns.B = class extends ns.A {
    constructor() {
        super();
        alert(this.Field);
    }

    //Field = 0;    

    Virtual() {
        this.Field = 123;
    }
}

ns.B.prototype.Field;

很抱歉在这里打扰您,但我不知道在哪里报告此问题的正确位置。

标签: javascriptes6-class

解决方案


来自https://github.com/tc39/proposal-class-fields#execution-of-initializer-expressions

当评估字段初始值设定项时...

基类:在构造函数执行的开始...

派生类:就在 super() 返回之后...

插图:

class A {
    constructor() {
        console.log('A constructor start');
        this.Virtual();
        console.log('A constructor end');
    }

    Field = (() => { console.log('A field init'); return 1})()

    Virtual() {
    }
};

class B extends A {
    constructor() {
        console.log('B constructor start')
        super();
        console.log('B constructor end')
    }

    Field = (() => { console.log('B field init'); return 2})()

    Virtual() {
        console.log('B virtual')
        this.Field = 123;
    }
};

console.log(new B())

也就是说,在您的代码中,Field = 0发生在 之后this.Field = 123,从而覆盖它。声明的顺序无关紧要。

如果您对此行为有疑问并希望讨论它,https://github.com/tc39/proposal-class-fields/issues将是正确的地方。


推荐阅读