JS-ES5模拟super与多级继承(一)

参考文章函数

  1. js多层继承 super方法

本系列文章对js es5实现多级继承作一个学习和探究, 第三篇给出最终的模拟代码及测试用例.学习

简单的父-子继承

// 父类A
function A(a){
    this.a = a;
}

A.prototype.sayA = function(){
    console.log(this.a);
};

// 子类B
function B(a, b){
    this._super.call(this, a);
    this.b = b;
}

// 原型链继承
Object.assign(B.prototype, A.prototype, {
    constructor: B, 
    _super: A
});

B.prototype.sayB = function(){
    console.log(this.b);
};

var b = new B(1, 2);
b.sayA();   // 1
b.sayB();   // 2

这里我用了_super关键字表示了继承的父类, Object.assign()方法能够将其附加到子类实例对象上, 用起来会方便一点.测试

可是, 比较致命的一点是, 这种方式不适用于多级继承, 我所定义的_super反而成了限制.this

// 父类A
function A(a){
    this.a = a;
}

A.prototype.sayA = function(){
    console.log(this.a);
};

// 子类B
function B(a, b){
    this._super.call(this, a);
    this.b = b;
}

// 原型链继承
Object.assign(B.prototype, A.prototype, {
    constructor: B, 
    _super: A
});

B.prototype.sayB = function(){
    console.log(this.b);
};

// 子类C
function C(a, b, c){
    this._super.call(this, a, b);
    this.c = c;
}

// 原型链继承
Object.assign(C.prototype, B.prototype, {
    constructor: C, 
    _super: B
});

C.prototype.sayC = function(){
    console.log(this.c);
};

var c = new C(1, 2, 3);
c.sayA();
c.sayB();
c.sayC();

上面的代码看起来彷佛没什么错误, 可是执行时, 会栈溢出, 在B类函数体的this._super.call(this, a);这一行.es5

VM4484:10 Uncaught RangeError: Maximum call stack size exceeded
    at C.B [as _super] (<anonymous>:10:11)
    at C.B [as _super] (<anonymous>:11:17)

缘由在于, c在实例化时构造函数调用父类B的构造函数, 但用的是call方法, B类构造函数在执行时this的值为c的实例, 而this._super的值又是B, 因而就在B的构造函数里一直循环..net

要解决这个问题, _super变量就不能绑定在this上, 可是好像也没有好的方法绑定在子类自己, 除非在子类中用父类的类名显示调用父类的同名方法. 但这样耦合性太强, 稍不注意就会出错(尤为是代码复制时).prototype

参考文章1中有错误, 不存在__super__属性, 但它给了我一个启示, super不必定非得是变量, 也能够是一个函数, 由函数的执行结果做为父类对象也是一种方法.code

相关文章
相关标签/搜索