ES5 有 6 種方式可以實(shí)現(xiàn)繼承,分別為:
1. 原型鏈繼承
原型鏈繼承的基本思想是利用原型讓一個引用類型繼承另一個引用類型的屬性和方法舆床。
缺點(diǎn):
該原型的引用類型屬性會被所有的實(shí)例共享蟀给。
無法給父類構(gòu)造函數(shù)傳參瓮增。
2. 借用構(gòu)造函數(shù)
借用構(gòu)造函數(shù)的技術(shù)巩步,其基本思想為:
在子類型的構(gòu)造函數(shù)中使用call()
或apply()
方法調(diào)用超類型構(gòu)造函數(shù)。
優(yōu)點(diǎn):
可以向超類傳遞參數(shù)
解決了原型中包含引用類型值被所有實(shí)例共享的問題
缺點(diǎn):
- 方法都在構(gòu)造函數(shù)中定義愉阎,無法實(shí)現(xiàn)函數(shù)的復(fù)用
- 超類型原型中定義的方法對于子類型而言都是不可見的绞蹦,所以無法繼承原型上的屬性和方法。
3. 組合繼承(原型鏈 + 借用構(gòu)造函數(shù))
組合繼承指的是將原型鏈和借用構(gòu)造函數(shù)技術(shù)組合到一塊榜旦,從而發(fā)揮二者之長的一種繼承模式幽七。基本思路:
使用原型鏈實(shí)現(xiàn)對原型屬性和方法的繼承溅呢,通過借用構(gòu)造函數(shù)來實(shí)現(xiàn)對實(shí)例屬性的繼承澡屡,既通過在原型上定義方法來實(shí)現(xiàn)了函數(shù)復(fù)用,又保證了每個實(shí)例都有自己的屬性咐旧。
缺點(diǎn):
- 無論什么情況下驶鹉,都會調(diào)用兩次超類型構(gòu)造函數(shù):一次是在創(chuàng)建子類型原型的時候,另一次是在子類型構(gòu)造函數(shù)內(nèi)部铣墨。
優(yōu)點(diǎn):
可以向超類傳遞參數(shù)
每個實(shí)例都有自己的屬性
實(shí)現(xiàn)了函數(shù)復(fù)用
4. 原型式繼承
原型繼承的基本思想:
借助原型可以基于已有的對象創(chuàng)建新對象室埋,同時還不必因此創(chuàng)建自定義類型。
在 object()
函數(shù)內(nèi)部伊约,先創(chuàng)建一個臨時性的構(gòu)造函數(shù)姚淆,然后將傳入的對象作為這個構(gòu)造函數(shù)的原型,最后返回了這個臨時類型的一個新實(shí)例屡律,從本質(zhì)上講肉盹, object()
對傳入的對象執(zhí)行了一次淺拷貝。
ECMAScript6通過新增 Object.create()
方法規(guī)范了原型式繼承疹尾。這個方法接收兩個參數(shù):一個用作新對象原型的對象和(可選的)一個為新對象定義額外屬性的對象(可以覆蓋原型對象上的同名屬性)上忍,在傳入一個參數(shù)的情況下, Object.create()
和 object()
方法的行為相同纳本。
在沒有必要創(chuàng)建構(gòu)造函數(shù)窍蓝,僅讓一個對象與另一個對象保持相似的情況下,原型式繼承是可以勝任的繁成。
缺點(diǎn):
同原型鏈實(shí)現(xiàn)繼承一樣吓笙,包含引用類型值的屬性會被所有實(shí)例共享。
5. 寄生式繼承
寄生式繼承是與原型式繼承緊密相關(guān)的一種思路巾腕。寄生式繼承的思路與寄生構(gòu)造函數(shù)和工廠模式類似面睛,即創(chuàng)建一個僅用于封裝繼承過程的函數(shù),該函數(shù)在內(nèi)部已某種方式來增強(qiáng)對象尊搬,最后再像真地是它做了所有工作一樣返回對象叁鉴。
基于 person
返回了一個新對象 -—— person2
,新對象不僅具有 person
的所有屬性和方法佛寿,而且還有自己的 sayHi()
方法幌墓。在考慮對象而不是自定義類型和構(gòu)造函數(shù)的情況下,寄生式繼承也是一種有用的模式。
缺點(diǎn):
使用寄生式繼承來為對象添加函數(shù)常侣,會由于不能做到函數(shù)復(fù)用而效率低下蜡饵。
同原型鏈實(shí)現(xiàn)繼承一樣,包含引用類型值的屬性會被所有實(shí)例共享胳施。
6. 寄生組合式繼承
所謂寄生組合式繼承溯祸,即通過借用構(gòu)造函數(shù)來繼承屬性,通過原型鏈的混成形式來繼承方法舞肆,基本思路:
不必為了指定子類型的原型而調(diào)用超類型的構(gòu)造函數(shù)焦辅,我們需要的僅是超類型原型的一個副本,本質(zhì)上就是使用寄生式繼承來繼承超類型的原型胆绊,然后再將結(jié)果指定給子類型的原型。寄生組合式繼承的基本模式如下所示:
第一步:創(chuàng)建超類型原型的一個副本
第二步:為創(chuàng)建的副本添加
constructor
屬性第三步:將新創(chuàng)建的對象賦值給子類型的原型
至此欧募,我們就可以通過調(diào)用 inheritPrototype
來替換為子類型原型賦值的語句:
優(yōu)點(diǎn):
只調(diào)用了一次超類構(gòu)造函數(shù)压状,效率更高。避免在 SuberType.prototype
上面創(chuàng)建不必要的跟继、多余的屬性种冬,與其同時,原型鏈還能保持不變舔糖。
因此寄生組合繼承是引用類型最理性的繼承范式娱两。