Javascript:为什么在子类中声明一个属性会将超类中的相同属性重写为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)

它打印出名称变量是未定义的

B { name: undefined, status: true }

我很确定B中的name属性重写了A中的name特性,但为什么A构造函数不将新的name变量指定为传递给它的值呢?

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

当您设置时

class A {
name
}

这声明了一个类字段。这还不是一个标准,这是第四阶段的一个提议。它可能会改变,但不会改变太多。第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);

最新更新