JavaScript組合繼承詳解
阿新 • • 發佈:2021-11-05
目錄
- 1、前言
- 2、原型鏈繼承
- 3、建構函式繼承
- 4、組合繼承
1、前言
首先學習繼承之前,要對原型鏈有一定程度的瞭解。
不瞭解可以去先閱讀我另一篇文章,裡面對原型鏈有一個較為詳細的說明: 原型鏈詳解。
如果已經瞭解請繼續。
之前寫過一篇博文將繼承方式全部列出來了,不過我發現一口氣看完過於長了,也不利於吸收知識,所以我先將組合繼承部分劃分出來,後續會把寄生部分補上。
2、原型鏈繼承
父類例項作為子類的原型
子類創造的兩個例項的隱式原型__proto__
指向父類的那個例項
而父類的例項的隱式原型__proto__
又指向父類的原型father.prototype
根據原型鏈的特性,所有子類的例項能夠繼承父類原型上的屬性。
閱覽以下這張圖可以配合程式碼理解清晰:
//父類 function father() { this.fatherAttr = ["fatherAttr"]; } //父類的原型上的屬性 father.prototype.checkProto = "checkProto"; //子類 function child() {} // 將father例項作為child這個建構函式的原型 child.prototype = new father(); child.prototype.constructor = child; //兩個子類例項 const test1 = new child(); const test2 = new child(); console.log("測試1:"); console.log("test1:",test1); console.log("test2:",test2); console.log("test1.fatherAttr:",test1.fatherAttr); console.log("test2.fatherAttr:",test2.fatherAttr); console.log("測試2:"); test1.fatherAttr.push("newAttr"); console.log("test1.fatherAttr:",test2.fatherAttr); console.log("測試3:"); console.log("test1.checkProto:",test1.checkProto);
特點:
- 兩個例項物件都沒有
fatherAttr
屬性,但是因為父類的例項會擁有fatherAttr
屬性,且現在父類的例項作為child的原型,根據原型鏈,他們可以共享到自己的建構函式child
的原型上的屬性。(測試1) - 因為只有一個父類的例項作為他們的原型,所以所有例項共享了一個原型上的屬性
fatherAttr
,當原型上的屬性作為引用型別時,此處是陣列,test1
新增一個新內容會導致test2
上的fatherAttr
也改變了。(測試2)(缺點) child
建構函式不能傳遞入參。(缺點)- 例項可以訪問到父類的原型上的屬性,因此可以把可複用方法定義在父類原型上。(測試3)
3、建構函式繼承
將父類上的this
繫結到子類,也就是當子類創造例項時會在子類內部呼叫父類的建構函式,父類上的屬性會拷貝到子類例項上,所以例項會繼承這些屬性。
//父類 function father(params) { this.fatherAttr = ["fatherAttr"]; this.params = params; } //父類的原型上的屬性 father.prototype.checkProto = "checkProto"; //子類 function child(params) { father.call(this,params); } //兩個子類例項 const test1 = new child("params1"); const test2 = new child("params2"); console.log("測試1:"); console.log("test1:",test2.fatherAttr); console.log("測試3:"); console.log("test1.checkProto:",test1.checkProto);
特點:
- 兩個例項物件都擁有了拷貝來的
fatherAttr
屬性,所以沒有共享屬性,創造一個例項就得拷貝一次父類的所有屬性,且因為不能繼承父類原型,所以方法不能複用,被迫拷貝方法。(測試1)(缺點) test1
新增一個新內容只是改變了test1
自己的屬性,不會影響到test2
。(測試2)child
建構函式可以傳遞引數,定製自己的屬性。(測試1)- 例項不能繼承父類的原型上的屬性。(測試3)(缺點)
4、組合繼承
結合原型鏈繼承和建構函式繼承,可以根據兩種繼承特點進行使用。
//父類 function father(params) { this.fatherAttr = ["fatherAttr"]; this.params = params; } //父類的原型上的屬性 father.prototype.checkProto = "checkProto"; //子類 function child(params) { //第二次呼叫了父類建構函式 father.call(this,params); } // 將father例項作為child建構函式的原型 child.prototype = new father();//第一次呼叫了父類建構函式 child.prototype.constructor = child; //兩個例項 const test1 = new child("params1");//從這裡跳轉去子類建構函式第二次呼叫了父類建構函式 const test2 = new child("params2"); console.log("測試1:"); console.log("test1:",test1.checkProto); console.log("測試4:http://www.cppcns.com"); delete test1.fatherAttr console.log("test1:",test1); console.log("test1.fatherAttr:",test1.fatherAttr);
特點:
- 兩個例項物件都擁有了拷貝來的
fatherAttr
屬性,創造一個例項就得拷貝一次父類的所有屬性(建構函式繼承特點,測試1),但是能訪問父類原型,可以把複用方法定義在父類原型上。(原型鏈繼承特點,測試1) test1
新增一個新內容只是改變了test1自己的屬性,不會影響到test2。(建構函式繼承特點,測試2)child
建構函式可以傳遞引數,定製自己的屬性。(建構函式繼承特點,測試1)- 例項能繼承父類的原型上的屬性。(原型鏈繼承特點,測試3)
- 呼叫了兩次父類的建構函式,生成兩份例項,建立子類原型鏈一次,用子類建立例項時,子類內部裡面一次,第二次覆蓋了第一次。(缺點)
- 因為呼叫兩次父類建構函式,如果用delete刪除實http://www.cppcns.com例上拷貝來的
fatherAttr
屬性,例項仍然擁有隱式原型指向的父類例項上的fatherAttr
屬性。(原型鏈繼承特點,測試4)(缺點)
到此這篇關於Script組合繼承詳解的文章就介紹到這了,更多相關JavaScript組合繼承內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!