JavaScript組合繼承詳解
1、前言
首先學(xué)習(xí)繼承之前,要對(duì)原型鏈有一定程度的了解。
不了解可以去先閱讀我另一篇文章,里面對(duì)原型鏈有一個(gè)較為詳細(xì)的說(shuō)明:JavaScript 原型鏈詳解。
如果已經(jīng)了解請(qǐng)繼續(xù)。
之前寫(xiě)過(guò)一篇博文將繼承方式全部列出來(lái)了,不過(guò)我發(fā)現(xiàn)一口氣看完過(guò)于長(zhǎng)了,也不利于吸收知識(shí),所以我先將組合繼承部分劃分出來(lái),后續(xù)會(huì)把寄生部分補(bǔ)上。
2、原型鏈繼承
父類實(shí)例作為子類的原型
子類創(chuàng)造的兩個(gè)實(shí)例的隱式原型__proto__
指向父類的那個(gè)實(shí)例
而父類的實(shí)例的隱式原型__proto__
又指向父類的原型father.prototype
根據(jù)原型鏈的特性,所有子類的實(shí)例能夠繼承父類原型上的屬性。
閱覽以下這張圖可以配合代碼理解清晰:
//父類 function father() { this.fatherAttr = ["fatherAttr"]; } //父類的原型上的屬性 father.prototype.checkProto = "checkProto"; //子類 function child() {} // 將father實(shí)例作為child這個(gè)構(gòu)造函數(shù)的原型 child.prototype = new father(); child.prototype.constructor = child; //兩個(gè)子類實(shí)例 const test1 = new child(); const test2 = new child(); console.log("測(cè)試1:"); console.log("test1:", test1); console.log("test2:", test2); console.log("test1.fatherAttr:", test1.fatherAttr); console.log("test2.fatherAttr:", test2.fatherAttr); console.log("測(cè)試2:"); test1.fatherAttr.push("newAttr"); console.log("test1.fatherAttr:", test1.fatherAttr); console.log("test2.fatherAttr:", test2.fatherAttr); console.log("測(cè)試3:"); console.log("test1.checkProto:", test1.checkProto);
特點(diǎn):
- 兩個(gè)實(shí)例對(duì)象都沒(méi)有
fatherAttr
屬性,但是因?yàn)楦割惖膶?shí)例會(huì)擁有fatherAttr
屬性,且現(xiàn)在父類的實(shí)例作為child的原型,根據(jù)原型鏈,他們可以共享到自己的構(gòu)造函數(shù)child
的原型上的屬性。(測(cè)試1) - 因?yàn)橹挥幸粋€(gè)父類的實(shí)例作為他們的原型,所以所有實(shí)例共享了一個(gè)原型上的屬性
fatherAttr
,當(dāng)原型上的屬性作為引用類型時(shí),此處是數(shù)組,test1
添加一個(gè)新內(nèi)容會(huì)導(dǎo)致test2
上的fatherAttr
也改變了。(測(cè)試2)(缺點(diǎn)) child
構(gòu)造函數(shù)不能傳遞入?yún)?。(缺點(diǎn))- 實(shí)例可以訪問(wèn)到父類的原型上的屬性,因此可以把可復(fù)用方法定義在父類原型上。(測(cè)試3)
3、構(gòu)造函數(shù)繼承
將父類上的this
綁定到子類,也就是當(dāng)子類創(chuàng)造實(shí)例時(shí)會(huì)在子類內(nèi)部調(diào)用父類的構(gòu)造函數(shù),父類上的屬性會(huì)拷貝到子類實(shí)例上,所以實(shí)例會(huì)繼承這些屬性。
//父類 function father(params) { this.fatherAttr = ["fatherAttr"]; this.params = params; } //父類的原型上的屬性 father.prototype.checkProto = "checkProto"; //子類 function child(params) { father.call(this, params); } //兩個(gè)子類實(shí)例 const test1 = new child("params1"); const test2 = new child("params2"); console.log("測(cè)試1:"); console.log("test1:", test1); console.log("test2:", test2); console.log("test1.fatherAttr:", test1.fatherAttr); console.log("test2.fatherAttr:", test2.fatherAttr); console.log("測(cè)試2:"); test1.fatherAttr.push("newAttr"); console.log("test1.fatherAttr:", test1.fatherAttr); console.log("test2.fatherAttr:", test2.fatherAttr); console.log("測(cè)試3:"); console.log("test1.checkProto:", test1.checkProto);
特點(diǎn):
- 兩個(gè)實(shí)例對(duì)象都擁有了拷貝來(lái)的
fatherAttr
屬性,所以沒(méi)有共享屬性,創(chuàng)造一個(gè)實(shí)例就得拷貝一次父類的所有屬性,且因?yàn)椴荒芾^承父類原型,所以方法不能復(fù)用,被迫拷貝方法。(測(cè)試1)(缺點(diǎn)) test1
添加一個(gè)新內(nèi)容只是改變了test1
自己的屬性,不會(huì)影響到test2
。(測(cè)試2)child
構(gòu)造函數(shù)可以傳遞參數(shù),定制自己的屬性。(測(cè)試1)- 實(shí)例不能繼承父類的原型上的屬性。(測(cè)試3)(缺點(diǎn))
4、組合繼承
結(jié)合原型鏈繼承和構(gòu)造函數(shù)繼承,可以根據(jù)兩種繼承特點(diǎn)進(jìn)行使用。
//父類 function father(params) { this.fatherAttr = ["fatherAttr"]; this.params = params; } //父類的原型上的屬性 father.prototype.checkProto = "checkProto"; //子類 function child(params) { //第二次調(diào)用了父類構(gòu)造函數(shù) father.call(this, params); } // 將father實(shí)例作為child構(gòu)造函數(shù)的原型 child.prototype = new father();//第一次調(diào)用了父類構(gòu)造函數(shù) child.prototype.constructor = child; //兩個(gè)實(shí)例 const test1 = new child("params1");//從這里跳轉(zhuǎn)去子類構(gòu)造函數(shù)第二次調(diào)用了父類構(gòu)造函數(shù) const test2 = new child("params2"); console.log("測(cè)試1:"); console.log("test1:", test1); console.log("test2:", test2); console.log("test1.fatherAttr:", test1.fatherAttr); console.log("test2.fatherAttr:", test2.fatherAttr); console.log("測(cè)試2:"); test1.fatherAttr.push("newAttr"); console.log("test1.fatherAttr:", test1.fatherAttr); console.log("test2.fatherAttr:", test2.fatherAttr); console.log("測(cè)試3:"); console.log("test1.checkProto:", test1.checkProto); console.log("測(cè)試4:"); delete test1.fatherAttr console.log("test1:", test1); console.log("test1.fatherAttr:", test1.fatherAttr);
特點(diǎn):
- 兩個(gè)實(shí)例對(duì)象都擁有了拷貝來(lái)的
fatherAttr
屬性,創(chuàng)造一個(gè)實(shí)例就得拷貝一次父類的所有屬性(構(gòu)造函數(shù)繼承特點(diǎn),測(cè)試1),但是能訪問(wèn)父類原型,可以把復(fù)用方法定義在父類原型上。(原型鏈繼承特點(diǎn),測(cè)試1) test1
添加一個(gè)新內(nèi)容只是改變了test1自己的屬性,不會(huì)影響到test2。(構(gòu)造函數(shù)繼承特點(diǎn),測(cè)試2)child
構(gòu)造函數(shù)可以傳遞參數(shù),定制自己的屬性。(構(gòu)造函數(shù)繼承特點(diǎn),測(cè)試1)- 實(shí)例能繼承父類的原型上的屬性。(原型鏈繼承特點(diǎn),測(cè)試3)
- 調(diào)用了兩次父類的構(gòu)造函數(shù),生成兩份實(shí)例,創(chuàng)建子類原型鏈一次,用子類創(chuàng)建實(shí)例時(shí),子類內(nèi)部里面一次,第二次覆蓋了第一次。(缺點(diǎn))
- 因?yàn)檎{(diào)用兩次父類構(gòu)造函數(shù),如果用delete刪除實(shí)例上拷貝來(lái)的
fatherAttr
屬性,實(shí)例仍然擁有隱式原型指向的父類實(shí)例上的fatherAttr
屬性。(原型鏈繼承特點(diǎn),測(cè)試4)(缺點(diǎn))
到此這篇關(guān)于JavaScript組合繼承詳解的文章就介紹到這了,更多相關(guān)JavaScript組合繼承內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用JavaScript練習(xí)動(dòng)畫(huà)最好的方式封面過(guò)渡
這篇文章主要為大家介紹了使用JavaScript練習(xí)動(dòng)畫(huà)最好的方式封面過(guò)渡實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07Astro Islands靜態(tài)頁(yè)面交互式UI組件
這篇文章主要為大家介紹了Astro Islands靜態(tài)頁(yè)面交互式UI組件使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08reduce探索lodash.reduce實(shí)現(xiàn)原理解析
這篇文章主要為大家介紹了reduce探索lodash.reduce實(shí)現(xiàn)原理示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02微信小程序 scroll-view組件實(shí)現(xiàn)列表頁(yè)實(shí)例代碼
這篇文章主要介紹了微信小程序 scroll-view組件實(shí)現(xiàn)列表頁(yè)實(shí)例代碼的相關(guān)資料,scroll-view組件介紹scroll-view是微信小程序提供的可滾動(dòng)視圖組件,其主要作用是可以用來(lái)做手機(jī)端經(jīng)常會(huì)看到的上拉加載 ,需要的朋友可以參考下2016-12-12TypeScript 內(nèi)置高級(jí)類型編程示例
這篇文章主要為大家介紹了TypeScript 內(nèi)置高級(jí)類型編程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09