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

多繼承

我們知道多繼承是面向?qū)ο蟮恼Z言中比較糾結(jié)的一個問題,有好處也存在缺陷。這方面我們不多討論。就javascript而言,要實現(xiàn)多繼承是比較簡單的,因為javascript中函數(shù)可以接受任意個數(shù)目的參數(shù),這就使問題變得簡單了。

我們創(chuàng)建一個multi函數(shù),接受任意數(shù)目的對象,實現(xiàn)方法就是在復制屬性的循環(huán)外面包裹一層循環(huán)接收不同參數(shù)對象的函數(shù)。

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;
}

下面我們測試這個函數(shù),創(chuàng)建三個對象,一個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
});

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

Paste_Image.png

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

寄生式繼承

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

下面創(chuàng)建一個對象

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

實現(xiàn)寄生式繼承

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;
}

寄生式繼承實現(xiàn)的步驟

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

借用構(gòu)造函數(shù)

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

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

上面這段代碼首先定義了一個父類的構(gòu)造函數(shù)

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

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

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

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

借用構(gòu)造函數(shù)并且復制原型

其實解決上面那個自身屬性被繼承兩次的問題也很簡單,我們首先調(diào)用apply函數(shù)繼承父類的自身屬性,然后在復制原型屬性就可以了,這個方法我們之前已經(jīng)討論過就是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

以上

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

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容