js組合模式和寄生組合模式的區別研究

2021-09-12 17:25:09 字數 3385 閱讀 1419

最近在閱讀《js權威指南》的繼承這一章,對於組合模式和寄生組合模式的區別有點混淆,在多次重讀以及嘗試之後,得到一些心得。

結合了建構函式繼承時可以為每個屬性重新初始化,構造乙個副本的優點,以及原型鏈繼承時一次定義處處共享的優點。
下面看具體的例子

/*js*/

function supertype(name)

supertype.prototype.getsupername = function ()

function subtype(name, age)

subtype.prototype.getsubage = function ()

var instance1 = new subtype('maria',24)

instance1.color.push('black')

console.log(instance1.color) // ['red','blue','green','black']

var instance2 = new subtype('jack',33)

console.log(instance2.color) // ['red','blue','green']

可以看到即使父類有引用物件,子類兩個例項的物件之間也不會互相影響。

這個例子最大程度上地優化了**,將方法放在原型鏈上,而通過子類建構函式裡的supertype.call(),為每個子類物件初始化了父類物件裡面的屬性,這些屬性就變成了子類獨享的。組合繼承成為js最常用的繼承模式。

但組合模式也不是沒有缺點。它的缺點在於:

無論在什麼情況下,都會呼叫兩次超型別建構函式,一次是在建立子型別原型的時候,另一次是在子型別建構函式的內部。
但令我百思不得其解的是,從上面給出的例子來看,組合繼承並沒有呼叫兩次超型別建構函式。當例項化subtype的時候有通過supertype.call()呼叫一次過一次supertype。同時,instance1和instance2都是subtype物件。那麼,第二次呼叫從何而來?

其實,上面的例子是並不完整的。兩個例項實際上只繼承了超型別的屬性,卻沒有繼承超型別的方法。

我們在例項化subtype的時候,實際上就自動給例項化物件建立了乙個新的原型物件,這個原型物件跟超型別的原型物件沒有什麼關係。所以subtype並沒有繼承getsupername()方法。

下面為子型別繼承父型別原型的例子:

/*js*/

function supertype(name)

supertype.prototype.getsupername = function ()

function subtype(name, age)

subtype.prototype = new supertype()

subtype.prototype.constructor = subtype

subtype.prototype.getsubage = function ()

var instance1 = new subtype()

instance1.color.push('black')

console.log(instance1.color)

var instance2 = new subtype()

console.log(instance2.color)

在這個例子中,我們來看一下instance1的組成:

在第一次呼叫supertype的時候,subtype.prototype會得到兩個屬性:colorname,它們也是supertype的例項屬性,不過現在位於subtype的原型上面。

在例項化subtype時呼叫了第二次supertype,這個時候subtype例項物件多了兩個namecolor的屬性,這兩個屬性屬於例項屬性,會覆蓋掉在subtype原型物件的屬性。

為了解決組合繼承這種無論如何都會呼叫兩次的問題,便可以引用寄生組合式繼承。

寄生組合式繼承是在原型式繼承的基礎上做的。

原型式繼承時道格拉斯·克羅克福德在2023年提出來的。主要目的是可以基於已有的物件建立新的物件,而不必因此建立自定義型別。

具體**如下:

function object(o) 

f.prototype = o

return new f()

}

通過將o賦給f的原型,再返回乙個原型為o的新物件。

而寄生組合式繼承在此基礎上的**為:

function inheritprototype(supertype,subtype)

function supertype(name)

supertype.prototype.getsupername = function ()

function subtype(name, age)

inheritprototype(supertype,subtype) //呼叫inheritprototype方法替換子類的原型

subtype.prototype.getsubage = function ()

var instance1 = new subtype('maria',24)

instance1.color.push('black')

console.log(instance1.color) // ['red','blue','green','black']

var instance2 = new subtype('jack',33)

console.log(instance2.color) // ['red','blue','green']

寄生組合式繼承在組合繼承的基礎上做了改進,只需要呼叫一次inheritprototype函式,就可以把supertype物件的原型屬性繼承給subtype物件,同時subtype例項的原型物件依然指向subtype函式。

ecmascript把object()做了改進,變成了object.create()方法,所以inheritprototype方法的第一行可以寫成:

var prototype = object.create(supertype.prototype)
對比組合模式和寄生組合模式:

js組合模式和寄生組合模式的區別研究

最近在閱讀 js權威指南 的繼承這一章,對於組合模式和寄生組合模式的區別有點混淆,在多次重讀以及嘗試之後,得到一些心得。結合了建構函式繼承時可以為每個屬性重新初始化,構造乙個副本的優點,以及原型鏈繼承時一次定義處處共享的優點。下面看具體的例子 js function supertype name s...

js組合模式和寄生組合模式的區別研究

最近在閱讀 js權威指南 的繼承這一章,對於組合模式和寄生組合模式的區別有點混淆,在多次重讀以及嘗試之後,得到一些心得。結合了建構函式繼承時可以為每個屬性重新初始化,構造乙個副本的優點,以及原型鏈繼承時一次定義處處共享的優點。下面看具體的例子 js function supertype name s...

組合模式 寄生組合繼承實戰新聞列表

所謂組合模式,就是把一堆結構分解出來,組成在一起,現實中很多這樣的例子,如 1 肯德基 就是一種組合模式,比如雞腿堡 一般是是由乙個雞腿堡,一包薯條,一杯可樂等組成的 2 組裝的台式電腦同理,由主機板,電源,記憶體條,顯示卡,機箱,顯示器,外設等組成的 把乙個成型的產品組成部件,分成乙個個獨立的部件...