JavaScript ES6类扩展没有超级
是否有可能在ES6中扩展一个类而不调用super
方法来调用父类?
编辑:这个问题可能是误导。 是我们必须调用super()
还是缺less一些东西?
例如:
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来运行这个
ES2015(ES6)类的规则基本上归结为:
- 在一个子类的构造函数中,只有在调用
super
才能使用它。 - 如果ES6类构造函数是子类,则必须调用
super
,否则必须显式返回一些对象来代替未初始化的对象。
这归结于ES2015规范的两个重要部分。
第8.1.1.3.4节定义了决定this
function的逻辑。 类的重要组成部分是,它有可能处于"uninitialized"
状态,并且在这种状态下,试图使用this
将会抛出exception。
第9.2.2节, [[Construct]]
,它定义了通过new
或super
调用的函数的行为。 当调用一个基类的构造函数时, this
在[[Construct]]
第8步被初始化,但是对于所有其他的情况, this
是未初始化的。 在构造结束时, GetThisBinding
,所以如果super
还没有被调用(因此初始化),或者没有返回一个显式的replace对象,构造函数调用的最后一行会抛出一个exception。
有多个答案和评论指出, super
必须是constructor
内的第一行。 这是完全错误的。 @loganfsmyth答案有要求的必要参考,但归结为:
inheritance( extends
)的构造函数必须在使用之前和返回之前调用super
,即使this
不使用
看到下面的片段(在Chrome中工作…),看看为什么在调用super
之前有声明(不使用this
)是有意义的。
'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());
只是注册发布这个解决scheme,因为这里的答案不满足我至less,因为实际上有一个简单的方法来解决这个问题。 调整你的类创build模式来覆盖子方法中的逻辑,同时只使用超级构造函数并将构造函数的参数转发给它。
正如你不要在你的子类本身中创build一个构造函数,而只是引用在相应的子类中覆盖的方法。
这意味着你可以从你自己的构造函数中解脱出来,并且避免使用常规的方法 – 当你让自己select你想要调用的超级(完全)的时候,可以重写并且不强制执行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");
新的es6类语法只是原型的“旧”es5“类”的其他符号。 因此,如果不设置原型(基类),就不能实例化特定的类。
这就像把奶酪放在你的三明治上而没有做到。 在制作三明治之前 ,你也不能放奶酪,所以…
…在super()
调用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); }
编辑:find这个在developer.mozilla.org
:
When used in a constructor, the super keyword appears alone and must be used before the this keyword can be used.
资源
尝试:
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();
演示
如果你打算开发下面的OOP概念,我会推荐使用OODK-JS 。
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); });
简单的解决scheme:我认为它明显不需要解释。
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()。 隐藏的默认构造函数将被自动包含在你的子类中。 但是,如果在子类中包含构造函数,则必须在该构造函数中调用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
阅读此以获取更多信息。