我的问题是了解类如何将值分配给属性,以及如何在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);