參考文章git
參考文章1中提供了一個思路, _super
不必定要是一個變量, 也能夠是一個函數, 只要它能返回咱們指望的父級對象就能夠了. 下面是我對它給出的源碼的一些修改和註釋, 另外有3個測試示例.github
/* * @author: general * @github: https://gist.github.com/generals-space/a75cfca06e1f8d463022e0e02446c363 */ /* * 要想擁有_super()方法, 必須繼承SuperExtend類. * 注意: * 1. inherits方法中不要再在assign時爲子類添加指向父類自己的屬性了, 會出問題的. * 2. 當須要使用_super()方法調用父類的某個方法時, 必需要保證子類有同名方法, 須要經過子類的方法調用父類方法才行 */ function SuperExtend(){} SuperExtend.prototype._super = function(){ // caller調用者應該會是子類的成員方法對象, 或是子類構造函數自己 var caller = arguments.callee.caller; // 這裏先獲得this所屬的構造函數類 var chain = this.constructor; var parent = null; // 沿繼承鏈一直向上遍歷, 至少要遍歷到SuperExtend的第一個子類 // 目標是**找到主調函數到底屬於繼承鏈上的哪一層級, 而後才能獲得這個調用者的父類, 也就是咱們須要的super對象** while(chain && chain.prototype){ // 對象的隱式原型`__proto__`屬性是一個指針, 它指向**構造本對象的**, **構造函數類**, **的原型**. // 可是因爲inherits的自定義繼承機制, chain.__proto__指向的是父級構造函數類(chain自己爲子級構造函數類) parent = chain.__proto__; // 若是調用者正好是構造函數類自己, 說明是在構造函數類的函數體中調用的, // 直接返回父級構造函數類自己 if(caller == chain) return parent; // 若是調用者不是子級構造函數類, 就應該是原型中的方法了. var props = Object.getOwnPropertyNames(chain.prototype); for(var i = 0; i < props.length; i ++){ // 這裏雖然相等, 但有多是當前類從上一層父類繼承而來的屬性, 而當前類自己並無定義過這個方法. // 須要進一步確認, 即確認父類原型上沒有與它徹底相同的方法(固然, 方法名可能同樣). if(caller == chain.prototype[props[i]] && caller != parent.prototype[props[i]]){ return parent.prototype; } } chain = parent; } return chain; }; /* * function: 自定義通用繼承方法. * 使用方法: inherits(子類, 父類) */ function inherits(subClass, superClass){ Object.assign(subClass.prototype, superClass.prototype, { constructor: subClass, }); // 創建這種聯繫後, 至關於subClass成了superClass的實例了 // 基本等價於subClass.prototype = superClass Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
3個測試示例以下函數
// 測試用例1. 基本測試 function A(a){ this.a = a; } inherits(A, SuperExtend); A.prototype.sayHi = function(){ console.log(this.a); }; function B(a, b){ this._super().call(this, a); this.b = b; } inherits(B, A); B.prototype.sayHi = function(){ this._super().sayHi.call(this); console.log(this.a, this.b); }; function C(a, b, c){ // 這裏獲得的是父級構造函數類自己, 直接call調用便可 this._super().call(this, a, b); this.c = c; } inherits(C, B); C.prototype.sayHi = function(){ // 這裏獲得的是父級構造函數類的原型對象 this._super().sayHi.call(this); console.log(this.a, this.b, this.c); }; var c = new C(2, 5, 8); c.sayHi();
// 測試用例2. 驗證同層級函數間調用的狀況 function A(a){ this.a = a; } inherits(A, SuperExtend); A.prototype.sayA = function(){ this.sayB(); }; A.prototype.sayB = function(){ console.log(this.a); }; function B(a, b){ this._super().call(this, a); this.b = b; } inherits(B, A); B.prototype.sayB = function(){ this._super().sayB.call(this); console.log(this.a, this.b); }; function C(a, b, c){ // 這裏獲得的是父級構造函數類自己, 直接call調用便可 this._super().call(this, a, b); this.c = c; } inherits(C, B); var c = new C(2, 5, 8); c.sayA();
// 測試用例3. 驗證主調函數與被調函數不一樣名的狀況 function A(a){ this.a = a; } inherits(A, SuperExtend); A.prototype.sayA = function(){ console.log(this.a); }; function B(a, b){ this._super().call(this, a); this.b = b; } inherits(B, A); B.prototype.sayB = function(){ this._super().sayA.call(this); console.log(this.a, this.b); }; function C(a, b, c){ // 這裏獲得的是父級構造函數類自己, 直接call調用便可 this._super().call(this, a, b); this.c = c; } inherits(C, B); var c = new C(2, 5, 8); c.sayB();