JS繼承與工廠構(gòu)造及原型設(shè)計(jì)模式詳解
序言
我們?cè)谇耙黄恼?a href="http://www.dbjr.com.cn/article/251607.htm" target="_blank">《JS精粹,原型鏈繼承和構(gòu)造函數(shù)繼承的 “毛病”》 ,提到了:原型鏈繼承、構(gòu)造函數(shù)繼承、組合繼承;
在另一篇文章《驀然回首,“工廠、構(gòu)造、原型”設(shè)計(jì)模式,正在燈火闌珊處》,提到了:我們用于創(chuàng)建對(duì)象的三種設(shè)計(jì)模式:工廠設(shè)計(jì)模式、構(gòu)造設(shè)計(jì)模式、原型設(shè)計(jì)模式;
至此,我們可以明顯的感受到:JS 要實(shí)現(xiàn)面向?qū)ο螅ɡ^承的能力),離不開這 3 種設(shè)計(jì)模式;
原型鏈 + 構(gòu)造函數(shù) = 組合繼承
本篇帶來一個(gè)新的繼承方式:寄生繼承,它由工廠模式和構(gòu)造函數(shù)模式組成,即
工廠+構(gòu)造函數(shù) = 寄生繼承
正文
正是由于:原型鏈繼承和構(gòu)造函數(shù)繼承的 “毛病”
- 原型鏈繼承:所有繼承的屬性和方法都會(huì)在對(duì)象實(shí)例間共享,無法做到實(shí)例私有。
- 構(gòu)造函數(shù)繼承:子類不能訪問父類原型上的方法。
組合繼承應(yīng)運(yùn)而生:
function SuperType(name){ this.name = name; this.colors = ["red", "blue", "green"]; } function SubType(name, age){ SuperType.call(this, name) // 構(gòu)造函數(shù)繼承 (兩次調(diào)用父類構(gòu)造函數(shù)) this.age = age; } SuperType.prototype.sayName = function() { console.log(this.name); } SubType.prototype = new SuperType() // 原型鏈繼承 (一次調(diào)用父類構(gòu)造函數(shù)) SubType.prototype.sayAge = function() { console.log(this.age); } let s1 = new SubType("Nicholas", 29) let s2= new SubType("Greg", 27) s1.colors.push("yellow") console.log(s1.colors) // ['red', 'blue', 'green', 'yellow'] console.log(s2.colors) // ['red', 'blue', 'green'] s1.sayName() // Nicholas s2.sayName() // Greg s1.sayAge() // 29 s2.sayAge() // 27
但是呢?這樣做,會(huì)有效率問題,父類構(gòu)造函數(shù)始終會(huì)被調(diào)用兩次:一次是在子類構(gòu)造函數(shù)中調(diào)用,另一次在是創(chuàng)建子類原型時(shí)調(diào)用。
本質(zhì)上,子類原型最終是要包含超類對(duì)象的所有實(shí)例屬性,子類構(gòu)造函數(shù)只要在執(zhí)行時(shí)重寫自己的原型就行了。
這個(gè)時(shí)候有一個(gè)新的思路!
不通過調(diào)用父類構(gòu)造函數(shù)給子類原型賦值,而是取得父類原型的一個(gè)副本。使用寄生式繼承來繼承父 類原型,然后將返回的新對(duì)象賦值給子類原型。
核心代碼是:通過工廠的方式,增強(qiáng)一個(gè)新對(duì)象:
function createAnother(original){ let clone = Object(original); // 通過調(diào)用函數(shù)創(chuàng)建一個(gè)新對(duì)象 clone.sayHi = function() { // 以某種方式增強(qiáng)這個(gè)對(duì)象 console.log("hi"); }; return clone; // 返回這個(gè)對(duì)象 }
將組合代碼改造一下,完整代碼是:
function inheritPrototype(subType, superType) { let prototype = Object(superType.prototype); // 創(chuàng)建對(duì)象 prototype.constructor = subType; // 增強(qiáng)對(duì)象 subType.prototype = prototype; // 賦值對(duì)象 } function SuperType(name) { this.name = name; this.colors = ["red", "blue", "green"]; } function SubType(name, age) { SuperType.call(this, name); // 構(gòu)造函數(shù)繼承(只調(diào)了一次) this.age = age; } SuperType.prototype.sayName = function() { console.log(this.name); }; inheritPrototype(SubType, SuperType); // 寄生繼承 SubType.prototype.sayAge = function() { console.log(this.age); }; let s1 = new SubType("Nicholas", 29) let s2= new SubType("Greg", 27) s1.colors.push("yellow") console.log(s1.colors) // ['red', 'blue', 'green', 'yellow'] console.log(s2.colors) // ['red', 'blue', 'green'] s1.sayName() // Nicholas s2.sayName() // Greg s1.sayAge() // 29 s2.sayAge() // 27
這里只調(diào)用了一次 SuperType 構(gòu)造函數(shù),避免了 SubType.prototype 上不必要也用不到的屬性;而且,原型鏈仍然保持不變,instanceof 操作符和 isPrototypeOf() 方法正常有效。
寄生式組合繼承可以算是【引用類型】繼承的最佳模式
os:不過這里的增強(qiáng)寫法,理解起來真是怪,為什么父類的顯示原型的構(gòu)造函數(shù)等于子類?
SuperType.prototype.constructor=== SubType // true
大概是為了,通過寄生實(shí)現(xiàn):父類、子類都由同一函數(shù)構(gòu)造;
SubType === SubType.prototype.constructor // true SuperType.prototype.constructor === SubType.prototype.constructor // true
結(jié)語
只要是寫 JS 的繼承,一定離不開:工廠、構(gòu)造、原型設(shè)計(jì)模式;
原型鏈 + 構(gòu)造函數(shù) = 組合繼承
工廠+構(gòu)造函數(shù) = 寄生繼承;
組合繼承和寄生繼承是最常用的兩種繼承方式。
......
u1s1,class 出來前,寫 JS 實(shí)現(xiàn)繼承,是真滴麻煩QAQ
以上就是JS繼承與工廠構(gòu)造及原型設(shè)計(jì)模式詳解的詳細(xì)內(nèi)容,更多關(guān)于JS繼承與設(shè)計(jì)模式的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
umi插件開發(fā)仿dumi項(xiàng)目實(shí)現(xiàn)頁面布局詳解
這篇文章主要為大家介紹了umi插件開發(fā)仿dumi項(xiàng)目實(shí)現(xiàn)頁面布局詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01JavaScript自動(dòng)化測(cè)試添加頁面DOM元素唯一ID方案示例
這篇文章主要為大家介紹了JavaScript自動(dòng)化測(cè)試添加頁面DOM元素唯一ID方案示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09lodash里to系列之將數(shù)據(jù)轉(zhuǎn)換成數(shù)字類型實(shí)現(xiàn)示例
這篇文章主要為大家介紹了lodash里to系列之將數(shù)據(jù)轉(zhuǎn)換成數(shù)字類型實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08微信小程序 轉(zhuǎn)發(fā)功能的實(shí)現(xiàn)
這篇文章主要介紹了微信小程序 轉(zhuǎn)發(fā)功能的實(shí)現(xiàn)的相關(guān)資料,這里提供實(shí)現(xiàn)方法及實(shí)例幫助大家學(xué)習(xí)理解,需要的朋友可以參考下2017-08-08arcgis?js完整懸停效果實(shí)現(xiàn)demo
這篇文章主要為大家介紹了arcgis?js完整懸停效果實(shí)現(xiàn)demo詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02微信小程序 本地存儲(chǔ)及登錄頁面處理實(shí)例詳解
這篇文章主要介紹了微信小程序 本地存儲(chǔ)實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-01-01ResizeObserver 監(jiān)視 DOM大小變化示例詳解
這篇文章主要為大家介紹了ResizeObserver 監(jiān)視 DOM大小變化示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10