【问题标题】:JS inheritence overriding in constructor?构造函数中的JS继承覆盖?
【发布时间】:2017-04-28 17:39:30
【问题描述】:

有人可以向我解释以下内容吗?

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)吗?因为一个道具覆盖了另一个? 我这里有什么问题吗?

【问题讨论】:

    标签: javascript inheritance ecmascript-6 es6-class ecmascript-next


    【解决方案1】:

    您忘记了派生类的构造函数中的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);
        }
      }
      

      【讨论】:

        【解决方案3】:

        您的代码无效。 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,但是你之前的日志没有理由消失……

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

        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 变量。

        【讨论】:

        • 想必 OP 正在使用 public class field 实验功能,但你是对的,它目前不是有效的 JS。
        • 是的,实际上我使用的是 babel,所以我不看编译后的 javascript。所以我永远不知道公共类字段实际编译成什么。也许我不应该在不知道它们是如何工作的情况下使用实验性功能,哈哈 :) 感谢您抽出时间回答我的问题。
        • 顺便说一句,我确实使用 pascal case 作为我的命名约定,我只是想写一个简单的例子,我可以在 StackOverflow 上发布。我实际上并没有在我的代码中使用“baseClass”lol :)
        • 很高兴知道骆驼案对您来说是一种反射。还是比蛇皮好... ^^
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-01-31
        • 2011-10-03
        • 2014-02-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-12-06
        相关资源
        最近更新 更多