前言
為大家分享js中最常見最詳細(xì)的繼承方式,接下來將一下面的幾個(gè)維度進(jìn)行展示說明
文章有點(diǎn)長(zhǎng),請(qǐng)耐心閱讀😁,有什么錯(cuò)誤理解的地方希望留言指出來
繼承方式
原型鏈繼承
相信小伙伴們都知道到原型鏈繼承(ECMAScript 中描述了原型鏈的概念,并將原型鏈作為實(shí)現(xiàn)繼承的主要方法),因?yàn)樵玩溊^承非常的強(qiáng)大,但是也有它的缺點(diǎn),接下來咱們就按照上面的維度看看原型鏈繼承到底是什么鬼
代碼實(shí)現(xiàn):(需要兩個(gè)構(gòu)造函數(shù)來完成一個(gè)原型鏈繼承)
// SuperType 構(gòu)造函數(shù)稱為超類 function SuperType (){ this.name='super'; this.friend=[]; this.property = true; } SuperType.prototype.getName=function(){ return this.name; } SuperType.prototype.getSuperValue = function(){ return this.property; }; // SubType 構(gòu)造函數(shù)稱為子類 function SubType(name,age){ this.name=name; this.age=age; this.subproperty = false; } SubType.prototype=new SuperType(); SubType.prototype.constrcutor=SubType; SubType.prototype.getAge=function(){ return this.age; } SubType.prototype.getSubValue = function (){ return this.subproperty; }; var child = new SubType('shiny',12); console.log(child.getName)//shiny console.log(child.getAge())//12
圖解部分 屬性
基本原理
使用類似作用域的原型鏈,進(jìn)行繼承查找
語言實(shí)現(xiàn)
定義兩個(gè)構(gòu)造函數(shù),分別為父類(SuperType)、子類(SubType),為了實(shí)現(xiàn)子類能夠使用父類的屬性(本身和原型上面的屬性)。重寫子類的原型,讓子類的原型指向父類實(shí)例,這樣子類的構(gòu)造函數(shù)就是父類的實(shí)例地址,實(shí)現(xiàn)子類可以使用父類的本身和原型上的屬性
優(yōu)點(diǎn)
子類可以通過原型鏈的查找,實(shí)現(xiàn)父類的屬性公用與子類的實(shí)例
缺點(diǎn)
借用構(gòu)造函數(shù)模式繼承
雖然原型鏈繼承很強(qiáng)大但是也有他的缺點(diǎn),借用構(gòu)造函數(shù)繼承可以解決原型鏈繼承的缺點(diǎn),開線面的解釋
代碼實(shí)現(xiàn):
// 把父類當(dāng)中一個(gè)函數(shù)使用 function SuperType(name){ this.name=name this.friend=['a','b'] } SuperType.prototype.getFriend=function(){ return this.firend } function SubType(name){ // 執(zhí)行父類函數(shù) SuperType.call(this,name); } var child = new SubType('shiny') var childRed = new SubType('red') console.log(child.name)//shiny console.log(childRed.name)//red child.firend.push('c') console.log(child.friend)//a,b,c console.log(childRed.friend)//a,b console.log(childRed.getFriend)//undefined
基本原理
使用call apply方法,通過執(zhí)行方法修改tihs (上下文),是的父級(jí)的this變成子類實(shí)例的this,這樣每個(gè)實(shí)例都會(huì)得到父類的屬性,實(shí)現(xiàn)引用屬性備份
使用場(chǎng)景
父類中需要一些子類使用共享的引用類型,并且子類可能會(huì)操作父類共享的引用類型
但是父類的非this綁定的屬性和方法是不可以使用的(放在父類prototype的屬性和方法)
語言實(shí)現(xiàn)
不要把父類當(dāng)中構(gòu)造函數(shù),當(dāng)中一個(gè)函數(shù)來處理這樣更容易理解,在子類的構(gòu)造函數(shù)中借用父類函數(shù)通過修改this來執(zhí)行,這樣子類的實(shí)例包含父類的屬性
優(yōu)點(diǎn)
缺點(diǎn)
組合繼承
上面的兩種繼承方式(原型鏈繼承+借用構(gòu)造函數(shù)繼承),都有自己優(yōu)缺點(diǎn),但是他們不是很完美,下面解釋一下組合繼承
代碼實(shí)現(xiàn):
function SuperType(name){ this.name=name; this.firend=['a','b'] } SuperType.prototype.getName=function(){ return this.name } function SubType(name,age){ this.age=age; SuperType.call(this,name) } SubType.prototype=new SuperType(); SubType.prototype.constrcutor = SubType; SubType.prototype.getAge=function(){ return this.age } var childShiny=new SubType('shiny',23); var childRed = new SubType('red',22); childShiny.firend.push('c'); childRed.firend.push('d'); console.log(childShiny.getName()); console.log(childShiny.getAge()); console.log(childRed.getName()); console.log(childRed.getAge()); console.log(childRed.friend);//[a,b,d] console.log(childShiny.friend);//[a,b,c]
基本原理
使用原型鏈的繼承實(shí)現(xiàn),通過原型查找功能來滿足原型鏈共享方法
使用借用構(gòu)造函數(shù)方法,使用實(shí)例備份父類共享引用類型備份
使用場(chǎng)景
得到原型鏈繼承和構(gòu)造函數(shù)繼承的優(yōu)點(diǎn),是被開發(fā)人員認(rèn)可的一種繼承方式,但是也有他的缺點(diǎn)
語言實(shí)現(xiàn)
定義兩個(gè)構(gòu)造函數(shù),分別為父類(SuperType)、子類(SubType),為了實(shí)現(xiàn)子類能夠使用父類的屬性(本身和原型上面的屬性)。重寫子類的原型,讓子類的原型指向父類實(shí)例,這樣子類的構(gòu)造函數(shù)就是父類的實(shí)例地址,實(shí)現(xiàn)子類可以使用父類的本身和原型上的屬性
不要把父類當(dāng)中構(gòu)造函數(shù),當(dāng)中一個(gè)函數(shù)來處理這樣更容易理解,在子類的構(gòu)造函數(shù)中借用父類函數(shù)通過修改this來執(zhí)行,這樣子類的實(shí)例包含父類的屬性
優(yōu)點(diǎn)
缺點(diǎn)
原型式繼承
話說上面的的組合繼承不是已經(jīng)被開發(fā)者認(rèn)可了嗎,原型式繼承是啥?下面咱們看看原型式繼承是什么樣的。
代碼實(shí)現(xiàn):
1 function object(o){ function F(){}; F.prototype=o; return new F() } var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; var personShiny = object(person); var personRed = object(person); console.log(personShiny.name)//Nicholas console.log(personRed.name)//Nicholas personShiny.friends.push('red'); personRed.friends.push('shiny'); console.log(personShiny.friends)//["Shelby", "Court", "Van","red","shiny"] //ECMAScript 5 通過新增 Object.create()方法規(guī)范化了原型式繼承。這個(gè)方法接收兩個(gè)參數(shù):一 //個(gè)用作新對(duì)象原型的對(duì)象和(可選的)一個(gè)為新對(duì)象定義額外屬性的對(duì)象。在傳入一個(gè)參數(shù)的情況下, //Object.create()與 object()方法的行為相同。 2 var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; var personShiny = Object.create(person); var personRed = Object.create(person); console.log(personShiny.name)//Nicholas console.log(personRed.name)//Nicholas personShiny.friends.push('red'); personRed.friends.push('shiny'); console.log(personShiny.friends)//["Shelby", "Court", "Van","red","shiny"]
基本原理
通過Object.create()方法來創(chuàng)建一個(gè)有基礎(chǔ)類的實(shí)例,這實(shí)例的__proto__指向基礎(chǔ)類
使用場(chǎng)景
在不使用構(gòu)造函數(shù)的情況下,只想讓一個(gè)對(duì)象與另一個(gè)對(duì)象保持類似的情況下
語言實(shí)現(xiàn)
需要?jiǎng)?chuàng)建一個(gè)基礎(chǔ)對(duì)象,作為一個(gè)新對(duì)象的基礎(chǔ)對(duì)象,通過object方法或者Object.create方法處理得到一個(gè)新實(shí)例,這個(gè)新實(shí)例上的__proto__指向基礎(chǔ)對(duì)象
優(yōu)點(diǎn)
再不用創(chuàng)建構(gòu)造函數(shù)的情況下,實(shí)現(xiàn)了原型鏈繼承,代碼量減少一部分
缺點(diǎn)
寄生繼承
咱們看了上面的原型式繼承,其實(shí)就是和原型鏈繼承差別不大,只是省去了構(gòu)造函數(shù)這一部,但是原型式繼承也是有缺點(diǎn)的(不能夠給備份的對(duì)象添加屬性),下面寄生繼承來解決。
代碼實(shí)現(xiàn):
// 和工廠模式非常類似,創(chuàng)建一個(gè)對(duì)象,增強(qiáng)一些功能并返回該對(duì)象 function createAnother(o){ var clone = Object(o); clone.sayHi=function(){ console.log('hi') } return clone } var person = { name:'shiny', friends:['a','b'] } var personShiny = createAnother(person); console.log(personShiny.sayHi())//Ho
基本原理
備份一個(gè)對(duì)象,然后給備份的對(duì)象進(jìn)行屬性添加,并返回
使用場(chǎng)景
在考不使用構(gòu)造函數(shù)的情況下實(shí)現(xiàn)繼承,前面示
范繼承模式時(shí)使用的 object()函數(shù)不是必需的;任何能夠返回新對(duì)象的函數(shù)都適用于此模式
語言實(shí)現(xiàn)
類似構(gòu)造函數(shù),通過一個(gè)執(zhí)行方法,里面創(chuàng)建一個(gè)對(duì)象,為該對(duì)象添加屬性和方法,然后返回
優(yōu)點(diǎn)
缺點(diǎn)
類似構(gòu)造函數(shù)一樣,創(chuàng)建寄生的方法需要在clone對(duì)象上面添加一些想要的屬性,這些屬性是放在clone上面的一些私有的屬性
寄生組合繼承
咱們看了上面的組合繼承看上去已經(jīng)很完美了,但是也有缺點(diǎn)(父類被實(shí)例化兩次、子類實(shí)例和子類的構(gòu)造函數(shù)都有相同的屬性),寄生組合就是來解決這些問題的
代碼實(shí)現(xiàn):
function inheritPrototype({SubType,SuperType}){ const prototype = Object(SuperType.prototype); prototype.constrcutor=SubType; SubType.prototype=prototype; } function SuperType(name){ this.name=name; this.friends=['a','b'] } SuperType.prototype.getName=function(){ return this.name; } function SubType(name,age){ this.age=age; SuperType.call(this,name) } inheritPrototype({SubType,SuperType}); SubType.prototype.getAge=function(){ return this.age } var SubTypeShiny = new SubType('Shiny',23); SubTypeShiny .friends.push('c') var SubTypeRed = new SubType('Red',21); SubTypeRed .friends.push('d') console.log(SubTypeShiny.getName())//Shiny console.log(SubTypeShiny.getAge())//22 console.log(SubTypeShiny.friends)//['a','b','c'] console.log( SubTypeRed.getName())//Red console.log( SubTypeRed.getAge())//21 console.log( SubTypeRed.friends)//['a','b','d']
基本原理
子類構(gòu)造函數(shù)內(nèi)通過call、apply方法進(jìn)行修改父類構(gòu)造函數(shù)的this和執(zhí)行父類構(gòu)造函數(shù),使的子類的實(shí)例擁有父類構(gòu)造函數(shù)的一些屬性,
結(jié)合子類的原型修改成父類構(gòu)造函數(shù)的原型,并把父類的原型的constructor指向子類構(gòu)造函數(shù)
使用場(chǎng)景
在考不使用構(gòu)造函數(shù)的情況下實(shí)現(xiàn)繼承,前面示
范繼承模式時(shí)使用的 object()函數(shù)不是必需的;任何能夠返回新對(duì)象的函數(shù)都適用于此模式
語言實(shí)現(xiàn)
極度類似組合寄生方式,只是修改了子類原型鏈繼承的方式,組合寄生是繼承父類的實(shí)例,寄生組合寄生則是通過一子類的原型繼承父類的原型,并把該原型的constructor指向子類構(gòu)造函數(shù)
優(yōu)點(diǎn)
缺點(diǎn)
暫無
下面是組合繼承和寄生組合繼承的原型圖對(duì)比
以上所述是小編給大家介紹的javascript繼承詳解整合,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com