JS构造函数中的继承覆盖?

3

有人能为我解释一下以下内容吗?

class BaseClass {
  prop = 88;
  constructor(){
    console.log("baseClass prop is ", this.prop);
  }
}
class DerivedClass extends BaseClass{
  prop = 83;
  constructor(){
    super();
    console.log("derivedClass prop is ", this.prop);
  }
}
new derivedClass();

输出结果为

baseClass prop is  88
derivedClass prop is  83

现在这两个属性不应该是一样的吗(83)?因为一个属性覆盖了另一个属性? 我是否理解错了?
3个回答

4
你忘记在派生类的构造函数中调用super()了。
这会调用基类的构造函数。因此,在派生类的构造函数之前,基类的构造函数已经运行完毕。
这意味着当执行基类的console.log语句时,prop变量仍然是88。

2

类属性在构造时从类层次结构底部向上初始化,随着构造函数的执行而执行。

  • 在基类中,它们会在构造函数内部自动初始化。
  • 在子类中,它们会在 super() 之后立即运行。

逻辑本质上是这样的。

this.prop = 88;
console.log("baseClass prop is ", this.prop);

this.prop = 83;
console.log("derivedClass prop is ", this.prop);

因为这些类是

class BaseClass {
  constructor(){
    this.prop = 88;
    console.log("baseClass prop is ", this.prop);
  }
}

class DerivedClass extends BaseClass {
  constructor(){
    super();
    this.prop = 83;
    console.log("derivedClass prop is ", this.prop);
  }
}

0

您的代码无效。ES6不是TypeScript,因此您的类属性必须在构造函数内声明。此外,您应该遵循一种编码约定,偏爱pascal case而不是camel case用于类名。以下是正确的语法:

class BaseClass {
  constructor(){
    this.prop = 88;
    console.log("BaseClass prop is", this.prop);
  }
}
    
class DerivedClass extends BaseClass {
  constructor(){
    super();
    this.prop = 83;
    console.log("DerivedClass prop is", this.prop);
  }
}
    
new DerivedClass();

那么,为什么我们有88和83呢?实际上,当您的派生类通过super()调用基类时,this.prop是88,并且您立即记录它。当super()执行结束时,this.prop变为83,但是您之前的日志没有消失的原因是没有理由...

现在,如果您出于某些原因想要私有属性,可以在构造函数之外声明它们,但是您需要使用IIFEs(立即调用函数表达式):

const BaseClass = (() => {
  let prop = 88;

  class BaseClass {
    constructor(){
      console.log("BaseClass prop is", prop);
    }
  }

  return BaseClass;
})();
 
const DerivedClass = (() => {
  let prop = 83;
    
  class DerivedClass extends BaseClass {
    constructor(){
      super();
      console.log("DerivedClass prop is", prop);
    }
  }
  
  return DerivedClass;
})();
    
new DerivedClass();

正如您所看到的,每个类都使用在其自己作用域中定义的prop变量。


可能原帖作者正在使用“public class field”实验性功能,但你说得对,目前它不是有效的JS。 - Felix Kling
是的,实际上我正在使用 Babel,所以我不看编译后的 JavaScript。因此,我从来不知道公共类字段实际上编译成什么样子。也许在不知道它们如何工作的情况下,我不应该使用实验性功能,哈哈 :) 感谢您抽出时间回答我的问题。 - Mohamed Abo El Soud
顺便说一下,我确实使用帕斯卡命名法作为我的命名约定,我只是想快速编写一个简单的示例,以便在StackOverflow上发布。我实际上不会在我的代码中使用“baseClass”哈哈 :) - Mohamed Abo El Soud
很高兴知道驼峰命名法对你来说是一种本能反应。比蛇形命名法好多了... ^^ - Badacadabra

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接