深入理解javascript中的繼承機制(4)

多繼承

我們知道多繼承是面向對象的語言中比較糾結的一個問題,有好處也存在缺陷。這方面我們不多討論。就javascript而言,要實現多繼承是比較簡單的,因為javascript中函數可以接受任意個數目的參數,這就使問題變得簡單了。

我們創建一個multi函數,接受任意數目的對象,實現方法就是在復制屬性的循環外面包裹一層循環接收不同參數對象的函數。

function multi() {
var n = {}, stuff, j = 0, len = arguments.length;
for (j = 0; j <len; j++) {
stuff = arguments[j];
for (var i in stuff) {
if (stuff.hasOwnProperty(i)) {
n[i] = stuff[i];
}
}
}
return n;
}

下面我們測試這個函數,創建三個對象,一個shape,一個twodee,一個匿名對象,傳遞一些屬性給Triangle。

var shape = {
name: 'Shape',
toString: function () {
return this.name;
}
};
var twoDee = {
name: '2D shape',
dimensions: 2
};
var triangle = multi(shape, twoDee, {
name: 'Triangle',
getArea: function () {
return this.side * this.height / 2;
},
side: 5,
height: 10
});

下面我們就在控制臺測試一下,多繼承函數是否起作用

Paste_Image.png

這里的multi函數使用的是淺復制,當然也可以修改為深復制的版本。
同時要注意一個問題,** 如果傳入的對象由同名屬性,那么屬性最后的值會和傳入的最后一個對象相同 **

寄生式繼承

寄生顧名思義,就是寄生在一個已有的對象,我們在創建對象的時候,寄生在已有的對象上,直接吸收其他對象已有的功能,擴展對象,并當作一個新對象返回。

下面創建一個對象

var twoD = {
name: '2D shape',
dimensions: 2
};

實現寄生式繼承

function triangle(s, h) {
var that = object(twoD);
that.name ='Triangle';
that.getArea = function () {
return this.side * this.height / 2;
};
that.side = s;
that.height = h;
return that;
}

寄生式繼承實現的步驟

  • 首先將已有的對象作為新對象的原型,繼承它的屬性,我們調用了之前的objec函數
  • 然后再給他添加其他屬性與方法

借用構造函數

這種繼承模式中,就是子對象的構造函數中調用父對象的構造函數,通過apply和call函數。
call和apply構造函數是什么呢?實際就是他們可以讓一個一個對象去借用另一個對象的方法,并為己所用,這是一種非常簡單的代碼重用的方法,實質上就是去改變函數的this值。
下面看實例

function Shape(id) {
this.id = id;
}
Shape.prototype.name = 'Shape';
Shape.prototype.toString = function () {
return this.name;
};

上面這段代碼首先定義了一個父類的構造函數

function Triangle() {
Shape.apply(this, arguments);
}
Triangle.prototype.name = 'Triangle';

我們調用父類的構造函數的apply方法,將triangle對象傳入進去,并傳入部分參數。
這樣的話,triangle對象會繼承Shape構造函數中的屬性,但不會繼承原型中的屬性。
如果你想繼承原型的屬性其實很簡單

function Triangle() {
Shape.apply(this, arguments);
}
Triangle.prototype = new Shape();
Triangle.prototype.name = 'Triangle';

但這樣有一個缺點,我們通過調用父類的構造函數,繼承了父類的自身屬性,通過原型繼承了父類的自身屬性和原型,這樣自身屬性實際上就被覆蓋了兩次。這是不高效的。
下面這個模式就可以更好的解決這個問題

借用構造函數并且復制原型

其實解決上面那個自身屬性被繼承兩次的問題也很簡單,我們首先調用apply函數繼承父類的自身屬性,然后在復制原型屬性就可以了,這個方法我們之前已經討論過就是extend2方法,可以復制原型屬性

function Shape(id) {
this.id = id;
}
Shape.prototype.name = 'Shape';
Shape.prototype.toString = function () {
return this.name;
};
function Triangle() {
Shape.apply(this, arguments);
}
extend2(Triangle, Shape);
Triangle.prototype.name = 'Triangle';

下面我們來測試一下

Paste_Image.png
Paste_Image.png

以上

終于我們將該講的繼承方式都講完了。
后續還有一片文章會將這些繼承模式歸類總結一下。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容