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

Javascript 如何在ES6中扩展类而不必使用super?,javascript,class,inheritance,ecmascript-6,Javascript,Class,Inheritance,Ecmascript 6,是否可以在ES6中扩展类而不调用super方法来调用父类 编辑:这个问题可能有误导性。这是我们必须调用的标准super(),还是我遗漏了什么? 例如: class Character { constructor(){ console.log('invoke character'); } } class Hero extends Character{ constructor(){ super(); // exception thrown here when

是否可以在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()
时,我遇到了一个范围问题->
这是未定义的

我正在用iojs运行这个程序——2.3.0版中的harmony

class Character {
   constructor(){
     if(Object.getPrototypeOf(this) === Character.prototype){
       console.log('invoke character');
     }
   }
}


class Hero extends Character{
  constructor(){
      super(); // throws exception when not called
      console.log('invoke hero');
  }
}
var hero = new Hero();

console.log('now let\'s invoke Character');
var char = new Character();

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

这就像在三明治上放奶酪而不做一样。你也不能在做三明治之前放奶酪,所以

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

// 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.

有多个答案和评论指出
super
必须是
构造函数的第一行。这完全是错误的@loganfsmyth答案包含要求的参考资料,但归结为:

继承(
extends
)构造函数必须在使用
this
和返回之前调用
super
,即使未使用
this

请参阅下面的片段(适用于Chrome…),了解在调用
super
之前使用语句(不使用
this
)的原因

“严格使用”;
var-id=1;
函数idgen(){
返回'ID:'+ID++;
}
阶级基础{
建造师(id){
this.id=id;
}
toString(){return JSON.stringify(this);}
}
类Derived1扩展了基{
构造函数(){
var anID=idgen()+':Derived1';
超级(anID);
this.derivedProp=this.baseProp*2;
}
}
警报(新的Derived1())ES2015(ES6)课程的规则基本上可以归结为:

  • 在子类构造函数中,
    this
    在调用
    super
    之前不能使用
  • 如果ES6类构造函数是子类,则必须调用
    super
    ,或者必须显式返回某个对象来代替未初始化的对象
  • 这可以归结为ES2015规范的两个重要部分

    第节定义了决定此
    在函数中是什么的逻辑。类的重要部分是,
    可能处于
    的“未初始化”
    状态,当处于该状态时,尝试使用
    将引发异常


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

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

    如中所示,您不在子类本身中创建构造函数,而只引用在相应子类中重写的方法

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

    可观察的类{
    构造函数(){
    返回此.ObjectConstructor(参数);
    }
    ObjectConstructor(默认值、选项){
    this.obj={type:“Observable”};
    log(“使用参数调用的可观察对象构造函数:”,参数);
    log(“obj是:”,this.obj);
    返回此.obj;
    }
    }
    类ArrayObservable扩展了Observable{
    ObjectConstructor(默认值、选项、其他选项){
    this.obj={type:“ArrayObservable”};
    log(“使用参数调用的ArrayObservable对象构造函数:”,参数);
    log(“obj是:”,this.obj);
    返回此.obj;
    }
    }
    类DomainObservable扩展了ArrayObservable{
    ObjectConstructor(默认值、域名、选项、dependent1、dependent2){
    this.obj=super.ObjectConstructor(默认值,选项);
    log(“使用参数调用的DomainObservable ObjectConstructor:”,参数);
    log(“obj是:”,this.obj);
    返回此.obj;
    }
    }
    var myBasicObservable=新的可观测值(“基本值”、“基本期权”);
    var myArrayObservable=新的ArrayObservable(“数组值”、“数组选项”、“更多数组选项”);
    var myDomainObservable=新的DomainObservable(“域值”、“域名”、“域选项”、“依赖性A”、“依赖性B”)如果您打算开发以下OOP概念,我建议您使用

    OODK(function($, _){
    
    var Character  = $.class(function ($, µ, _){
    
       $.public(function __initialize(){
          $.log('invoke character');
       });
    });
    
    var Hero = $.extends(Character).class(function ($, µ, _){
    
      $.public(function __initialize(){
          $.super.__initialize();
          $.log('invoke hero');
      });
    });
    
    var hero = $.new(Hero);
    });
    

    简单的解决办法:我认为这很清楚,不需要解释

    class ParentClass() {
        constructor(skipConstructor = false) { // default value is false
            if(skipConstructor) return;
            // code here only gets executed when 'super()' is called with false
        }
    }
    class SubClass extends ParentClass {
        constructor() {
            super(true) // true for skipping ParentClass's constructor.
            // code
        }
    }
    
    如果在子类中完全省略构造函数,则可以在子类中省略super()。“隐藏”默认构造函数将自动包含在子类中。但是,如果您确实在子类中包含构造函数,supe
    class ParentClass() {
        constructor(skipConstructor = false) { // default value is false
            if(skipConstructor) return;
            // code here only gets executed when 'super()' is called with false
        }
    }
    class SubClass extends ParentClass {
        constructor() {
            super(true) // true for skipping ParentClass's constructor.
            // code
        }
    }
    
    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
    
    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();
        }
    }
    
    parentMethod()
    childMethod()
    this === obj ? true
    obj instanceof A ? true
    obj instanceof B ? true