6種JavaScript繼承方式及優(yōu)缺點(diǎn)(小結(jié))
溫馨提示:想要更好的理解JS繼承方式,須了解構(gòu)造函數(shù)、原型對象、實(shí)例化對象、原型鏈等概念
第一種:原型鏈繼承
利用原型鏈的特點(diǎn)進(jìn)行繼承
function Parent(){ this.name = 'web前端'; this.type = ['JS','HTML','CSS']; } Parent.prototype.Say=function(){ console.log(this.name); } function Son(){}; Son.prototype = new Parent(); son1 = new Son(); son1.Say();
以上例子解釋:
①創(chuàng)建一個叫做Parent的構(gòu)造函數(shù),暫且稱為父構(gòu)造函數(shù),里面有兩個屬性name、type
②通過Parent構(gòu)造函數(shù)的屬性(即原型對象)設(shè)置Say方法,此時,Parent有2個屬性和1個方法
③創(chuàng)建一個叫做Son的構(gòu)造函數(shù),暫且稱為子構(gòu)造函數(shù)
④設(shè)置Son的屬性(即原型對象)值為父構(gòu)造函數(shù)Parent的實(shí)例對象,即子構(gòu)造函數(shù)Son繼承了父構(gòu)造函數(shù)Parent,此時Son也有2個屬性和1個方法
⑤對Son構(gòu)造函數(shù)進(jìn)行實(shí)例化,結(jié)果賦值給變量son1,即son1為實(shí)例化對象,同樣擁有2個屬性和1個方法
⑥輸出son1的Say方法,結(jié)果為"web前端"
優(yōu)點(diǎn):可以實(shí)現(xiàn)繼承
缺點(diǎn):
①因?yàn)镾on.prototype(即原型對象)繼承了Parent實(shí)例化對象,這就導(dǎo)致了所有Son實(shí)例化對象都一樣,都共享有原型對象的屬性及方法。代碼如下:
son1 = new Son(); son2 = new Son(); son1.type.push('VUE'); console.log(son1.type);//['JS','HTML','CSS','VUE'] console.log(son2.type);//['JS','HTML','CSS','VUE']
結(jié)果son1、son2都是['JS','HTML','CSS','VUE']
②Son構(gòu)造函數(shù)實(shí)例化對象無法進(jìn)行參數(shù)的傳遞
第二種:構(gòu)造函數(shù)繼承
通過構(gòu)造函數(shù)call方法進(jìn)行繼承,直接來看代碼:
function Parent(){ this.name = 'web前端'; this.type = ['JS','HTML','CSS']; } function Son(){ Parent.call(this); } son1 = new Son(); son1.type.push('VUE'); console.log(son1.type);//['JS','HTML','CSS','VUE'] son2 = new Son(); console.log(son2.type);//['JS','HTML','CSS']
以上例子解釋:
①創(chuàng)建父級構(gòu)造函數(shù)Parent,有name、type兩個屬性
②創(chuàng)建子級構(gòu)造函數(shù)Son,函數(shù)內(nèi)部通過call方法調(diào)用父級構(gòu)造函數(shù)Parent,實(shí)現(xiàn)繼承
③分別創(chuàng)建構(gòu)造函數(shù)Son的兩個實(shí)例化對象son1、son2,對son1的type屬性新增元素,son2沒有新增,結(jié)果不一樣,說明實(shí)現(xiàn)了獨(dú)立
優(yōu)點(diǎn):
①實(shí)現(xiàn)實(shí)例化對象的獨(dú)立性;
②還可以給實(shí)例化對象添加參數(shù)
function Parent(name){ this.name = name; } function Son(name){ Parent.call(this,name); } son1 = new Son('JS'); console.log(son1);//JS son2 = new Son('HTML'); console.log(son2);//HTML
缺點(diǎn):
①方法都在構(gòu)造函數(shù)中定義,每次實(shí)例化對象都得創(chuàng)建一遍方法,基本無法實(shí)現(xiàn)函數(shù)復(fù)用
②call方法僅僅調(diào)用了父級構(gòu)造函數(shù)的屬性及方法,沒有辦法調(diào)用父級構(gòu)造函數(shù)原型對象的方法
第三種:組合繼承
利用原型鏈繼承和構(gòu)造函數(shù)繼承的各自優(yōu)勢進(jìn)行組合使用,還是看代碼:
function Parent(name){ this.name = name; this.type = ['JS','HTML','CSS']; } Parent.prototype.Say=function(){ console.log(this.name); } function Son(name){ Parent.call(this,name); } Son.prototype = new Parent(); son1 = new Son('張三'); son2 = new Son('李四'); son1.type.push('VUE'); son2.type.push('PHP'); console.log(son1.type);//['JS','HTML','CSS','VUE'] console.log(son2.type);//['JS','HTML','CSS','PHP'] son1.Say();//張三 son2.Say();//李四
以上例子解釋:
①創(chuàng)建一個叫做Parent的構(gòu)造函數(shù),里面有兩個屬性name、type
②通過Parent構(gòu)造函數(shù)的屬性(即原型對象)設(shè)置Say方法,此時,Parent有2個屬性和1個方法
③創(chuàng)建子級構(gòu)造函數(shù)Son,函數(shù)內(nèi)部通過call方法調(diào)用父級構(gòu)造函數(shù)Parent,實(shí)現(xiàn)繼承
④子構(gòu)造函數(shù)Son繼承了父構(gòu)造函數(shù)Parent,此時Son也有2個屬性和1個方法
⑤分別創(chuàng)建構(gòu)造函數(shù)Son的兩個實(shí)例化對象son1、son2,傳不同參數(shù)、給type屬性新增不同元素、調(diào)用原型對象Say方法
優(yōu)點(diǎn):
①利用原型鏈繼承,實(shí)現(xiàn)原型對象方法的繼承
②利用構(gòu)造函數(shù)繼承,實(shí)現(xiàn)屬性的繼承,而且可以參數(shù)
組合函數(shù)基本滿足了JS的繼承,比較常用
缺點(diǎn):
無論什么情況下,都會調(diào)用兩次父級構(gòu)造函數(shù):一次是在創(chuàng)建子級原型的時候,另一次是在子級構(gòu)造函數(shù)內(nèi)部
第四種:原型式繼承
創(chuàng)建一個函數(shù),將參數(shù)作為一個對象的原型對象
function fun(obj) { function Son(){}; Son.prototype = obj; return new Son(); } var parent = { name:'張三' } var son1 = fun(parent); var son2 = fun(parent); console.log(son1.name);//張三 console.log(son2.name);//張三
以上例子解釋:
①創(chuàng)建一個函數(shù)fun,內(nèi)部定義一個構(gòu)造函數(shù)Son
②將Son的原型對象設(shè)置為參數(shù),參數(shù)是一個對象,完成繼承
③將Son實(shí)例化后返回,即返回的是一個實(shí)例化對象
優(yōu)缺點(diǎn):跟原型鏈類似
第五種:寄生繼承
在原型式繼承的基礎(chǔ)上,在函數(shù)內(nèi)部豐富對象
function fun(obj) { function Son() { }; Son.prototype = obj; return new Son(); } function JiSheng(obj) { var clone = fun(obj); clone.Say = function () { console.log('我是新增的方法'); } return clone; } var parent = { name: '張三' } var parent1 = JiSheng(parent); var parent2 = JiSheng(parent); console.log(parent2.Say==parent1.Say);// false
以上例子解釋:
①再原型式繼承的基礎(chǔ)上,封裝一個JiSheng函數(shù)
②將fun函數(shù)返回的對象進(jìn)行增強(qiáng),新增Say方法,最后返回
③調(diào)用JiSheng函數(shù)兩次,分別賦值給變量parent1、parent2
④對比parent1、parent2,結(jié)果為false,實(shí)現(xiàn)獨(dú)立
優(yōu)缺點(diǎn):跟構(gòu)造函數(shù)繼承類似,調(diào)用一次函數(shù)就得創(chuàng)建一遍方法,無法實(shí)現(xiàn)函數(shù)復(fù)用,效率較低
這里補(bǔ)充一個知識點(diǎn),ES5有一個新的方法Object.create(),這個方法相當(dāng)于封裝了原型式繼承。這個方法可以接收兩個參數(shù):第一個是新對象的原型對象(可選的),第二個是新對象新增屬性,所以上面代碼還可以這樣:
function JiSheng(obj) { var clone = Object.create(obj); clone.Say = function () { console.log('我是新增的方法'); } return clone; } var parent = { name: '張三' } var parent1 = JiSheng(parent); var parent2 = JiSheng(parent); console.log(parent2.Say==parent1.Say);// false
第六種:寄生組合繼承
利用組合繼承和寄生繼承各自優(yōu)勢
組合繼承方法我們已經(jīng)說了,它的缺點(diǎn)是兩次調(diào)用父級構(gòu)造函數(shù),一次是在創(chuàng)建子級原型的時候,另一次是在子級構(gòu)造函數(shù)內(nèi)部,那么我們只需要優(yōu)化這個問題就行了,即減少一次調(diào)用父級構(gòu)造函數(shù),正好利用寄生繼承的特性,繼承父級構(gòu)造函數(shù)的原型來創(chuàng)建子級原型。
function JiSheng(son,parent) { var clone = Object.create(parent.prototype);//創(chuàng)建對象 son.prototype = clone; //指定對象 clone.constructor = son; //增強(qiáng)對象 } function Parent(name){ this.name = name; this.type = ['JS','HTML','CSS']; } Parent.prototype.Say=function(){ console.log(this.name); } function Son(name){ Parent.call(this,name); } JiSheng(Son,Parent); son1 = new Son('張三'); son2 = new Son('李四'); son1.type.push('VUE'); son2.type.push('PHP'); console.log(son1.type);//['JS','HTML','CSS','VUE'] console.log(son2.type);//['JS','HTML','CSS','PHP'] son1.Say();//張三 son2.Say();//李四
以上例子解釋:
①封裝一個函數(shù)JiSheng,兩個參數(shù),參數(shù)1為子級構(gòu)造函數(shù),參數(shù)2為父級構(gòu)造函數(shù)
②利用Object.create(),將父級構(gòu)造函數(shù)原型克隆為副本clone
③將該副本作為子級構(gòu)造函數(shù)的原型
④給該副本添加constructor屬性,因?yàn)棰壑行薷脑蛯?dǎo)致副本失去默認(rèn)的屬性
優(yōu)缺點(diǎn):
組合繼承優(yōu)點(diǎn)、寄生繼承的有點(diǎn),目前JS繼承中使用的都是這個繼承方法
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
理解Javascript_07_理解instanceof實(shí)現(xiàn)原理
在《Javascript類型檢測》一文中講到了用instanceof來用做檢測類型,讓我們來回顧一下2010-10-10Javascript實(shí)現(xiàn)返回上一頁面并刷新的小例子
這篇文章主要介紹了Javascript實(shí)現(xiàn)返回上一頁面并刷新的小例子,有需要的朋友可以參考一下2013-12-12JavaScript實(shí)現(xiàn)單鏈表過程解析
這篇文章主要介紹了JavaScript實(shí)現(xiàn)單鏈表過程,鏈表中的元素在內(nèi)存中不必是連續(xù)的空間。鏈表的每個元素有一個存儲元素本身的節(jié)點(diǎn)和指向下一個元素的引用。下面請和小編一起進(jìn)入文章了解更多的詳細(xì)內(nèi)容吧2021-12-12微信小程序?qū)崿F(xiàn)根據(jù)字母選擇城市功能
這篇文章主要為大家詳細(xì)介紹了微信小程序中根據(jù)字母選擇城市的相關(guān)方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-08-08JavaScript中textRange對象使用方法小結(jié)
這篇文章主要介紹了JavaScript中textRange對象使用方法小結(jié),需要的朋友可以參考下2015-03-03