如何扩展一个类而不必在ES6中使用super?

xha*_*lix 86 javascript inheritance class ecmascript-6

是否可以在ES6中扩展一个类而不调用该super方法来调用父类?

编辑:这个问题可能会产生误导.它是我们必须打电话的标准super()还是我错过了什么?

例如:

class Character {
   constructor(){
      console.log('invoke character');
   }
}

class Hero extends Character{
  constructor(){
      super(); // exception thrown here when not called
      console.log('invoke hero');
  }
}

var hero = new Hero();
Run Code Online (Sandbox Code Playgroud)

当我没有调用super()派生类时,我遇到了范围问题 - >this is not defined

我用iojs运行这个 - 在v2.3.0中的和声

log*_*yth 137

ES2015(ES6)课程的规则基本上归结为:

  1. 在子类构造函数中,this直到super被调用才能使用.
  2. ES6类构造函数必须调用,super如果它们是子类,或者它们必须显式返回一些对象来取代未初始化的对象.

这归结为ES2015规范的两个重要部分.

8.1.1.3.4节定义了决定this函数内容的逻辑.类的重要部分是它可能this处于一种"uninitialized"状态,并且当处于这种状态时,尝试使用this将抛出一个异常.

9.2.2节,[[Construct]]定义了通过new或调用的函数的行为super.调用基类构造函数时,this在步骤#8初始化[[Construct]],但对于所有其他情况,this未初始化.在构造结束时,GetThisBinding调用,因此如果super尚未调用(因此初始化this),或者未返回显式替换对象,则构造函数调用的最后一行将引发异常.

  • 感谢您的编辑 - 它就在那里; 你可以`返回Object.create(new.target.prototype,...)`以避免调用超级构造函数. (8认同)
  • 你认为ES6中有可能从一个类继承而不在构造函数中调用`super()`吗? (4认同)
  • @Maximus参见[什么是"new.target"?](http://stackoverflow.com/q/32450516/1048572) (2认同)

Ami*_*mit 10

有多个答案和评论说明super 必须是内线的第一行constructor.这完全是错的.@loganfsmyth答案有必要的参考要求,但归结为:

Inheriting(extends)构造函数必须super在使用this之前和返回之前调用,即使this未使用它也是如此

请参阅下面的片段(适用于Chrome ...),了解为什么this在调用之前使用语句(不使用)可能有意义super.

'use strict';
var id = 1;
function idgen() {
  return 'ID:' + id++;
}

class Base {
  constructor(id) {
    this.id = id;
  }

  toString() { return JSON.stringify(this); }
}

class Derived1 extends Base {
  constructor() {
    var anID = idgen() + ':Derived1';
    super(anID);
    this.derivedProp = this.baseProp * 2;
  }
}

alert(new Derived1());
Run Code Online (Sandbox Code Playgroud)

  • `"请参阅下面的片段(适用于Chrome ...)"`打开chrome开发人员控制台,然后点击"运行代码段":"未捕获的ReferenceError:未定义`.当然,你可以在`super()`之前使用构造函数中的方法,但是之前你不能使用类中的方法! (2认同)

mar*_*cel 7

新的es6类语法只是带有原型的"旧"es5"类"的另一种表示法.因此,如果不设置其原型(基类),则无法实例化特定类.

这就像把奶酪放在你的三明治上而没有制作它.制作三明治之前你也不能放奶酪,所以......

... this在调用超类之前使用关键字super()也是不允许的.

// valid: Add cheese after making the sandwich
class CheeseSandwich extend Sandwich {
    constructor() {
        super();
        this.supplement = "Cheese";
    }
}

// invalid: Add cheese before making sandwich
class CheeseSandwich extend Sandwich {
    constructor() {
        this.supplement = "Cheese";
        super();
    }
}

// invalid: Add cheese without making sandwich
class CheeseSandwich extend Sandwich {
    constructor() {
        this.supplement = "Cheese";
    }
}
Run Code Online (Sandbox Code Playgroud)

如果未指定基类的构造函数,则使用以下定义:

constructor() {}
Run Code Online (Sandbox Code Playgroud)

对于派生类,使用以下默认构造函数:

constructor(...args) {
    super(...args);
}
Run Code Online (Sandbox Code Playgroud)

编辑:发现这个developer.mozilla.org:

When used in a constructor, the super keyword appears alone and must be used before the this keyword can be used.
Run Code Online (Sandbox Code Playgroud)

资源


Cho*_*ang 6

如果在子类中完全省略构造函数,则可以在子类中省略 super()。“隐藏”的默认构造函数将自动包含在您的子类中。但是,如果您确实在子类中包含构造函数,则必须在该构造函数中调用 super()。

class A{
   constructor(){
      this.name = 'hello';   
   }
}
class B extends A{
   constructor(){
      // console.log(this.name); // ReferenceError
      super();
      console.log(this.name);
   }
}
class C extends B{}  // see? no super(). no constructor()

var x = new B; // hello
var y = new C; // hello
Run Code Online (Sandbox Code Playgroud)

阅读本文了解更多信息。


Mic*_*wis 6

justyourimage 的答案是最简单的方法,但他的例子有点臃肿。这是通用版本:

class Base {
    constructor(){
        return this._constructor(...arguments);
    }

    _constructor(){
        // just use this as the constructor, no super() restrictions
    }
}

class Ext extends Base {
    _constructor(){ // _constructor is automatically called, like the real constructor
        this.is = "easy"; // no need to call super();
    }
}
Run Code Online (Sandbox Code Playgroud)

不要扩展 real constructor(),只需使用 fake_constructor()进行实例化逻辑。

请注意,此解决方案使调试变得烦人,因为您必须为每个实例化进入一个额外的方法。

  • 是的,这是迄今为止最简单的方法和最清晰的答案 - 我问的问题是...“为什么,上帝,为什么!?”... super() 不是自动的,这是有充分理由的。 ..您可能希望将特定参数传递给您的基类,因此您可以在实例化基类之前进行一些处理/逻辑/思考。 (2认同)