繁体   English   中英

Javascript:为什么在子类中声明一个属性会覆盖超类中的相同属性为空

[英]Javascript: Why does declaring a property in a subclass overwrite the same property in a super class as null

我的问题与理解类如何为属性赋值以及如何在 Javascript 中实例化对象有关。 我想更多地了解这个过程是如何工作的。

如果我创建两个类,其中第二个继承自第一个

class A {
    name

    constructor(name){
        this.name = name
    }
}

class B extends A {
    name
    status

    constructor(name, status){
        super(name)
        this.status = status
    }
}

然后创建一个类 B 的实例,当我将它打印到控制台时

x = new B('myClass', true)
console.log(x)

它打印出 name 变量未定义

B { name: undefined, status: true }

我很确定 B 中的 name 属性覆盖了 A 中的 name 属性,但是为什么 A 构造函数不将新的 name 变量分配为传递给它的值?

这是目前的正确行为(2020 年 10 月)。

当你设置

class A {
    name
}

这声明了一个类字段 这还不是标准,它是第 3 阶段的提案 它可能会改变,但不会太大。 第 3 阶段是候选阶段,可能包括完成改进。

无论如何,根据提案的当前规范,您所看到的都是正确的。 任何没有初始化器的类字段都设置为undefined 发生这种情况是因为您在B有另一个名为name类字段,但没有初始化程序。 在父构造函数中发生的赋值将被覆盖。

这是讨论此行为的提案的相关部分

没有初始值设定项的字段设置为undefined

无论是否存在初始值设定项,公共和私有字段声明都会在实例中创建一个字段。 如果没有初始化程序,则该字段设置为undefined 这与某些转译器实现略有不同,后者会完全忽略没有初始化程序的字段声明。

例如,在下面的示例中, new D将生成一个对象,其y属性是undefined ,而不是1

 class C { y = 1; } class D extends C { y; }

将没有初始值设定项的字段设置为undefined而不是擦除它们的语义是字段声明提供了一个可靠的基础,以确保创建的对象上存在属性。 这有助于程序员将对象保持在相同的一般状态,这可以使推理变得容易,有时在实现中更可优化。

这个例子是从MDN借来的,以表明这种行为不应该发生。

 class Animal { constructor(name) { this.name = name; } speak() { console.log(`${this.name} makes a noise.`); } } class Dog extends Animal { constructor(name) { super(name); // call the super class constructor and pass in the name parameter } speak() { console.log(`${this.name} barks.`); } } let d = new Dog('Mitzie'); d.speak(); // Mitzie barks.

如果您在 SO 中的代码段配置中选中Use BabelJS / ES2015复选框,则您的代码不会出现问题。

 class A { name; constructor(name){ this.name = name; } } class B extends A { name; status; constructor(name, status){ super(name); this.status = status; } } let a = new B('myClass',true); console.log(a);

但是如果你取消选中它...

 class A { name; constructor(name){ this.name = name; } } class B extends A { name; status; constructor(name, status){ super(name); this.status = status; } } let a = new B('myClass',true); console.log(a);

...相同的代码提供了您注意到的错误。

那么实际问题是什么以及如何解决这个问题? 不需要在子类中再次设置name 如果不这样做,结果如下:

 class A { name; constructor(name){ this.name = name; } } class B extends A { status; constructor(name, status){ super(name); this.status = status; } } let a = new B('myClass',true); console.log(a);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM