JavaScript寄生組合式繼承實(shí)例詳解
本文實(shí)例講述了JavaScript寄生組合式繼承。分享給大家供大家參考,具體如下:
其實(shí)《JavaScript高級(jí)程序設(shè)計(jì)》這本書中已經(jīng)有完整代碼了,只要把代碼讀懂就知道這個(gè)繼承是怎么回事。
首先,在js中,給對(duì)象定義屬性有兩種方式:
//通過執(zhí)行構(gòu)造函數(shù)設(shè)置屬性 function A(){ this.a = 1; } //通過原型設(shè)置屬性 A.prototype.b = 1;
所以:
一個(gè)類Sub要繼承另一個(gè)類Super,需要繼承父類的prototype下的屬性,還要執(zhí)行一下父類的構(gòu)造函數(shù)。
即一個(gè)類Sub要繼承另一個(gè)類Super,既要通過原型鏈實(shí)現(xiàn)對(duì)原型屬性和方法的繼承,又要通過在子類構(gòu)造函數(shù)內(nèi)調(diào)用父類構(gòu)造函數(shù)實(shí)現(xiàn)對(duì)實(shí)例屬性的繼承。
1. 繼承prototype下的屬性
上面可以看到,Super類的prototype下的屬性是沒有被繼承的,因此下面還需要繼承這一部分。
直接「=」肯定不行,因?yàn)镾ub.prototype中修改屬性后,不能影響Super.prototype里面的對(duì)象,即不能Sub.prototype=Super.prototype
。
首先寫一個(gè)創(chuàng)建對(duì)象副本的方法
function object(o){ function A(){} A.prototype = o var ox = new A() return ox }
上面的函數(shù)得到的對(duì)象ox,擁有了對(duì)象o的全部屬性(在原型鏈上),而修改ox的屬性,不會(huì)影響到o,相當(dāng)于把o復(fù)制了一份。
原型式繼承就是上面的“object”函數(shù),在很多類庫源碼中都能發(fā)現(xiàn)它的身影
簡(jiǎn)單而言,原型式繼承就是不用實(shí)例化父類了,直接實(shí)例化一個(gè)臨時(shí)副本實(shí)現(xiàn)了相同的原型鏈繼承。(即子類的原型指向父類副本的實(shí)例從而實(shí)現(xiàn)原型共享)
tips:總所周知,原型鏈繼承是子類的原型指向父類的實(shí)例從而實(shí)現(xiàn)原型共享,而原型式繼承是子類的原型指向父類副本的實(shí)例從而實(shí)現(xiàn)原型共享。
ECMAScirpt 5通過新增Object.create()
方法規(guī)范化了原型式繼承。
使用object方法,就可以將Super.prototype的屬性「復(fù)制」到Sub.prototype上了,當(dāng)然這兒還需要修正一下constructor的指向。
function inherit(subType,superType){ var prototype=Object.create(superType.prototype); prototype.constructor=subType; subType.prototype=prototype; }
2. 分別執(zhí)行父類和子類的構(gòu)造函數(shù),繼承這部分下的屬性:
//父類 function Super(){ this.sss=1 } //子類 function Sub(){ //arguments是Sub收到的參數(shù),將這個(gè)參數(shù)傳給Super Super.apply(this, arguments) } //實(shí)例 sub = new Sub()
Super.apply(this, arguments)
這一句,將Super類作為一個(gè)普通函數(shù)來執(zhí)行,但是Super類的this被換成了Sub類的this,Sub收到的參數(shù)也傳給了Super
最后執(zhí)行結(jié)果相當(dāng)于sub.sss=1
附上各種繼承方式的特點(diǎn)和優(yōu)缺點(diǎn)
曾經(jīng)一段時(shí)間因?yàn)閖avascript關(guān)于類實(shí)現(xiàn)繼承的不規(guī)范,導(dǎo)致各種各樣實(shí)現(xiàn)繼承的代碼;而實(shí)際上不管代碼怎么變,繼承都基于兩種方式:
1.通過原型鏈,即子類的原型指向父類的實(shí)例從而實(shí)現(xiàn)原型共享。
2.借用構(gòu)造函數(shù),即通過js的apply、call實(shí)現(xiàn)子類調(diào)用父類的屬性、方法;
原型鏈方式可以實(shí)現(xiàn)所有屬性方法共享,但無法做到屬性、方法獨(dú)享(例如Sub1修改了父類的函數(shù),其他所有的子類Sub2、Sub3...想調(diào)用舊的函數(shù)就無法實(shí)現(xiàn)了);
而借用構(gòu)造函數(shù)除了能獨(dú)享屬性、方法外還能在子類構(gòu)造函數(shù)中傳遞參數(shù),但代碼無法復(fù)用。總體而言就是可以實(shí)現(xiàn)所有屬性方法獨(dú)享,但無法做到屬性、方法共享(例如,Sub1新增了一個(gè)函數(shù),然后想讓Sub2、Sub3...都可以用的話就無法實(shí)現(xiàn)了,只能Sub2、Sub3...各自在構(gòu)造函數(shù)中新增)。
組合繼承就是把以上兩種繼承方式一起使用,把共享的屬性、方法用原型鏈繼承實(shí)現(xiàn),獨(dú)享的屬性、方法用借用構(gòu)造函數(shù)實(shí)現(xiàn),所以組合繼承幾乎完美實(shí)現(xiàn)了js的繼承;為什么說是“幾乎”?因?yàn)檎J(rèn)(dan)真(teng)的geek們發(fā)現(xiàn)組合繼承有一個(gè)小bug,實(shí)現(xiàn)的時(shí)候調(diào)用了兩次超類(父類),性能上不合格啊有木有!怎么解決呢?于是“寄生繼承”就出來了。
寄生繼承(原型式繼承)就是不用實(shí)例化父類了,直接實(shí)例化一個(gè)臨時(shí)副本實(shí)現(xiàn)了相同的原型鏈繼承。(即子類的原型指向父類副本的實(shí)例從而實(shí)現(xiàn)原型共享)
“寄生組合繼承”用了“寄生繼承”修復(fù)了“組合繼承”的小bug,從而讓js完美實(shí)現(xiàn)繼承了。
實(shí)例代碼:
function SuperType(name,colors){ this.name=name; this.colors=colors; } SuperType.prototype.getSuperProperty=function(){ return this.name; } function SubType(job,name,colors){ SuperType.call(this,name,colors); this.job=job; } SubType.prototype.getSubPrototype=function(){ return this.job; } function inherit(subType,superType){ var prototype=Object.create(superType.prototype); prototype.constructor=subType; subType.prototype=prototype; } inherit(SubType,SuperType); var instance=new SubType("doctor","John",["red","green"]); console.log(instance.getSubPrototype()); //輸出"doctor" console.log(instance.getSuperProperty()); //輸出"John",成功調(diào)用在父類原型定義的方法
屬性繼承代碼是SuperType.call(this,name,colors);
原型繼承代碼是inherit(SubType,SuperType);
更多關(guān)于JavaScript相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《javascript面向?qū)ο笕腴T教程》、《JavaScript錯(cuò)誤與調(diào)試技巧總結(jié)》、《JavaScript數(shù)據(jù)結(jié)構(gòu)與算法技巧總結(jié)》、《JavaScript遍歷算法與技巧總結(jié)》及《JavaScript數(shù)學(xué)運(yùn)算用法總結(jié)》
希望本文所述對(duì)大家JavaScript程序設(shè)計(jì)有所幫助。
相關(guān)文章
關(guān)于JS中match() 和 exec() 返回值和屬性的測(cè)試
這篇文章主要介紹了關(guān)于JS中match() 和 exec() 返回值和屬性的測(cè)試 的相關(guān)資料,需要的朋友可以參考下2016-03-03IE6 彈出Iframe層中的文本框“經(jīng)?!睙o法獲得輸入焦點(diǎn)
IE6間歇性精神障礙 彈出Iframe層中的文本框“經(jīng)常”無法獲得輸入焦點(diǎn)的解決方法。2009-12-12js實(shí)現(xiàn)簡(jiǎn)單排列組合的方法
這篇文章主要介紹了js實(shí)現(xiàn)簡(jiǎn)單排列組合的方法,可實(shí)現(xiàn)數(shù)學(xué)上排列組合算法功能,涉及JavaScript數(shù)組與字符串操作技巧,需要的朋友可以參考下2016-01-01js簡(jiǎn)單實(shí)現(xiàn)用戶注冊(cè)信息的校驗(yàn)代碼
這篇文章介紹了js簡(jiǎn)單實(shí)現(xiàn)用戶注冊(cè)信息的校驗(yàn)代碼,有需要的朋友可以參考一下2013-11-11淺析JavaScriptSerializer類的序列化與反序列化
本篇文章主要介紹了JavaScriptSerializer類 對(duì)象序列化與反序列化的方法、屬性以及實(shí)例代碼,有需要的朋友可以參考一下2016-11-11window.showModalDialog參數(shù)傳遞中含有特殊字符的處理方法
程序運(yùn)行出錯(cuò)經(jīng),過檢查發(fā)現(xiàn)傳遞的數(shù)據(jù)中出現(xiàn)了#等特殊字符,瀏覽器只取到#號(hào)前面的數(shù)據(jù),后面的被截?cái)?,下面為大家介紹下正確的處理方法2013-06-06uniapp?實(shí)現(xiàn)自定義縮略滾動(dòng)條效果
這篇文章主要介紹了uniapp?實(shí)現(xiàn)自定義縮略滾動(dòng)條,本文通過示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-08-08利用JS判斷字符串是否含有數(shù)字與特殊字符的方法小結(jié)
在我們?nèi)粘9ぷ鞯臅r(shí)候,利用javaScript判斷一個(gè)字符串中是否包括有數(shù)字和"-",在一些表單提交的地方,這是比較有用的常規(guī)判斷,這里收集有幾種不同的方法,最后還將簡(jiǎn)要介紹下isNAN函數(shù)的使用方法和例子,有需要的朋友們可以參考借鑒,下面來一起看看吧。2016-11-11