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

相關文章
相關標籤/搜索