最近在閱讀《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會得到兩個屬性:color
和name
,它們也是supertype的例項屬性,不過現在位於subtype的原型上面。
在例項化subtype時呼叫了第二次supertype,這個時候subtype例項物件多了兩個name
和color
的屬性,這兩個屬性屬於例項屬性,會覆蓋掉在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 組裝的台式電腦同理,由主機板,電源,記憶體條,顯示卡,機箱,顯示器,外設等組成的 把乙個成型的產品組成部件,分成乙個個獨立的部件...