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

IT技术 javascript class inheritance ecmascript-6
2021-01-29 01:51:07

是否可以在 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();

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

我在 v2.3.0 中使用 iojs --harmony 运行它

6个回答

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

  1. 在子类构造函数中,在调用this之前不能使用super
  2. super如果ES6 类构造函数是子类,则必须调用它们,否则它们必须显式返回某个对象以代替未初始化的对象。

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

8.1.1.3.4定义了决定this函数中内容的逻辑类的重要部分是它可能this处于某种"uninitialized"状态,当处于这种状态时,尝试使用this会抛出异常。

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

您应该添加如果省略构造函数会发生什么:将根据MDN使用默认构造函数
2021-03-13 01:51:07
您能否建议一种无需调用即可从类继承的方法super()
2021-03-29 01:51:07
你认为在 ES6 中可以在不调用super()构造函数的情况下从类继承吗?
2021-03-29 01:51:07
感谢您的编辑 - 现在就在那里;return Object.create(new.target.prototype, …)可以避免调用超级构造函数。
2021-04-05 01:51:07
2021-04-12 01:51:07

新的 es6 类语法只是带有原型的“旧”es5“类”的另一种表示法。因此,您不能在不设置其原型(基类)的情况下实例化特定类。

那就像把奶酪放在三明治上而不做。做三明治之前你也不能放奶酪,所以......

...this在调用超类 with 之前使用关键字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";
    }
}

如果没有为基类指定构造函数,则使用以下定义:

constructor() {}

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

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

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

When used in a constructor, the super keyword appears alone and must be used before the this keyword can be used.

来源

@marcel 我为愤世嫉俗道歉,但是: 1. 是关于引入一个在 OP 中不存在的新问题。2 是提醒您注意您的主张是错误的(情况仍然如此)
2021-03-13 01:51:07
@marcel - 看我的回答
2021-03-13 01:51:07
@amit 1. 现在我也不能用this了?!2. 我的 JS 类代表三明治,在 ES6 中你不能总是使用this. 我只是想解释 es6 类(用一个比喻),没有人需要这种破坏性/不必要的评论。
2021-03-29 01:51:07
1.在OP中,this根本没有使用。2. JS 不是三明治,在 ES5 中你总是可以使用this,甚至在调用你喜欢的任何其他函数之前(可能定义也可能不定义补充属性)
2021-03-30 01:51:07
所以如果我理解正确的话,当不调用 super() 时,我将无法在我的类 Hero 上使用类 Character 中的任何方法?但这似乎并不完全正确,因为我可以从基类调用方法。所以我想我在调用构造函数时只需要 super
2021-04-03 01:51:07

有多个答案和评论指出super 必须是里面的第一行constructor那简直是错误的。@loganfsmyth 回答有要求的必要参考,但归结为:

继承 ( 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());

@x-yuri 这是一个 5 年前的答案:-) 但是,我仍然认为它的value在于解释什么是有效代码或无效代码,而不是此类代码的用例。了解更多总是一件好事,即使您在任何时候都看不到用例。
2021-03-13 01:51:07
"See fragment below (works in Chrome...)"打开 chrome 开发者控制台并点击“运行代码片段”:Uncaught ReferenceError: this is not defined当然,您之前可以在构造函数中使用方法,super()之前不能使用类中的方法!
2021-03-14 01:51:07
this之前不能使用的super()(您的代码证明了这一点)与规范无关,而是与 javascript 的实现有关。所以,你必须在 'this' 之前调用 'super'。
2021-04-02 01:51:07
我会说这个例子很快而且很脏。抱歉我直率了。它表明这super不一定是第一个陈述。但我为什么要那样?在调用基本构造函数之前生成一个 id?为什么不将它用于所有类?derivedPropnull它至少提出了很多问题。你让它听起来像是你有一个实际应用的例子。但这个例子仍然是理论上的。
2021-04-06 01:51:07
@marcel - 我认为我们有很多困惑。我只是(一直)声明在使用 之前使用STATEMENTS是合法的super,而您声明this在调用之前使用是非法的super我们都是对的,只是彼此不理解:-)(这个例外是故意的,为了表明什么是不合法的——我什至将这个财产命名为“WillFail”)
2021-04-07 01:51:07

如果在子类中完全省略构造函数,则可以在子类中省略 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

阅读本文了解更多信息。

刚刚注册发布此解决方案,因为这里的答案至少不能让我满意,因为实际上有一个简单的方法可以解决这个问题。调整您的类创建模式以覆盖子方法中的逻辑,同时仅使用超级构造函数并将构造函数参数转发给它。

就像在您的子类中本身不创建构造函数一样,而是只引用在相应子类中被覆盖的方法。

这意味着您将自己从强加给您的构造函数功能中解放出来,并避免使用常规方法- 可以覆盖并且不会强制您选择是否、在哪里以及如何调用 super(完全可选)例如:

super.ObjectConstructor(...)

class Observable {
  constructor() {
    return this.ObjectConstructor(arguments);
  }

  ObjectConstructor(defaultValue, options) {
    this.obj = { type: "Observable" };
    console.log("Observable ObjectConstructor called with arguments: ", arguments);
    console.log("obj is:", this.obj);
    return this.obj;
  }
}

class ArrayObservable extends Observable {
  ObjectConstructor(defaultValue, options, someMoreOptions) {
    this.obj = { type: "ArrayObservable" };
    console.log("ArrayObservable ObjectConstructor called with arguments: ", arguments);
    console.log("obj is:", this.obj);
    return this.obj;
  }
}

class DomainObservable extends ArrayObservable {
  ObjectConstructor(defaultValue, domainName, options, dependent1, dependent2) {
    this.obj = super.ObjectConstructor(defaultValue, options);
    console.log("DomainObservable ObjectConstructor called with arguments: ", arguments);
    console.log("obj is:", this.obj);
    return this.obj;
  }
}

var myBasicObservable = new Observable("Basic Value", "Basic Options");
var myArrayObservable = new ArrayObservable("Array Value", "Array Options", "Some More Array Options");
var myDomainObservable = new DomainObservable("Domain Value", "Domain Name", "Domain Options", "Dependency A", "Depenency B");

干杯!

我需要一个“像我五岁一样解释”..我觉得这是一个非常深刻的答案,但很复杂,因此被忽略了
2021-03-25 01:51:07
@swyx:魔术在构造函数内部,其中“this”指的是不同类型的对象,具体取决于您创建的对象类型。例如,如果您正在构建一个新的 DomainObservable,则 this.ObjectConstructor 指的是不同的方法,即 DomainObserveable.ObjectConstructor ;而如果你正在构建一个新的 ArrayObservable, this.ObjectConstructor 指的是 ArrayObservable.ObjectConstructor 。
2021-03-26 01:51:07
看我的回答,我贴了一个更简单的例子
2021-03-30 01:51:07
我完全同意@swyx;这个答案做得太多了……我只是略读了一下,我已经累了。我感觉“像我五岁那样解释,真的要尿尿……”
2021-04-04 01:51:07