參考文章函數
本系列文章對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