ES6 javascript类继承,为什么我们需要从派生类调用super()

时间:2016-12-29 14:18:51

标签: javascript es6-class

在javascript ES6中,在继承中,
如果派生类有构造函数,为什么必须从派生构造函数调用super?

很少有失败的例子 - :

。基础与构造函数,但派生不调用超级 -

 class Base{constructor(){}}
    class Derived{constructor(){}}
    var d = new Derived(); // fails - ReferenceError: this is not defined

2 个答案:

答案 0 :(得分:3)

  

...似乎必须在基类中使用构造函数。

不是真的。如果您没有提供,one will be provided for you by the JavaScript engine。所以总会有一个(在这个意义上它是强制性的),但它不必明确编码。

当你根本没有定义构造函数时,JavaScript引擎为基类提供的默认值将如下所示:

constructor( ) { }

...派生类中的默认值如下所示:

constructor(...args) {
    super(...args);
}

您的示例失败的原因是Derived有明确的constructor,但constructor没有调用super。如果您明确定义一个,那么必须super的构造函数中调用Derived

  

如果派生类有构造函数,为什么必须从派生构造函数调用super?

因为您需要为超类提供对其必须执行的新对象进行任何初始化的机会。否则,超类不能保证它能正常工作,因为它可能依赖于构造函数的初始化。

所以:

  1. constructor移除Derived,使其成为您的第一个示例,以便JavaScript引擎提供默认构造函数,或

  2. super的构造函数中调用Derived

  3. 在评论中你问:

      

    但是如果基类没有任何构造函数,它仍然会失败,如果派生类有

    基类总是有一个构造函数,因为如果你没有提供一个(你在问题的代码中做过),就会提供一个默认值。所以你仍然需要打电话。虽然如果没有超类具有非默认构造函数,可以被指定为可选,但这会增加复杂性并使Derived的显式构造函数误导(不调用{{ 1}})。

    还有一些机械原因:在您致电super之前未定义this,但您可以在致电super之前做一些事情,因此拨打电话是必须在规范中处理super的机制。

答案 1 :(得分:1)

这不是强制性的,但是如果要为子类分配属性,则需要在构造函数中调用super,以便JavaScript解释器知道哪些属性属于父类,哪些属性属于父类。子类。

让我们举个例子。

在这种情况下,没有分配属性,只有方法,因此JavaScript会自动使用默认的空构造函数。

class Animal {
  move () {
    console.log('moving');
  }
}

class Dog extends Animal {
  bark () {
    console.log('barking');
  }
}

如果我们想要为子类分配属性,我们需要调用super

class Animal {
  move () {
    console.log('moving');
  }
}

class Dog extends Animal {
  constructor (name) {
    super();
    this.name = name;
  }
  bark () {
    console.log('barking');
  }
}

原因是JavaScript解释器无法知道传递给子类构造函数(name)的参数是属于父类还是属于子类。所以它需要prgrammer来指定它。