js中實現(xiàn)繼承的五種方法
借用構(gòu)造函數(shù)
這種技術的基本思想很簡單,就是在子類型構(gòu)造函數(shù)的內(nèi)部調(diào)用超類型的構(gòu)造函數(shù)。另外,函數(shù)只不過是在特定環(huán)境中執(zhí)行代碼的對象,因此通過使用apply()和call()方法也可以在新創(chuàng)建的對象上執(zhí)行構(gòu)造函數(shù)。
function Box(name){ this.name = name } Box.prototype.age = 18 function Desk(name){ Box.call(this, name) // 對象冒充,對象冒充只能繼承構(gòu)造里的信息 } var desk = new Desk('ccc') console.log(desk.name) // --> ccc console.log(desk.age) // --> undefined
從中可以看到,繼承來的只有實例屬性,而原型上的屬性是訪問不到的。這種模式解決了兩個問題,就是可以傳參,可以繼承,但是沒有原型,就沒有辦法復用。
組合繼承
function Box(name){ this.name = name } Box.prototype.run = function (){ console.log(this.name + '正在運行...') } function Desk(name){ Box.call(this, name) // 對象冒充 } Desk.prototype = new Box() // 原型鏈 var desk = new Desk('ccc') console.log(desk.name) // --> ccc desk.run() // --> ccc正在運行...
這種繼承方式的思路是:用使用原型鏈的方式來實現(xiàn)對原型屬性和方法的繼承,而通過借用構(gòu)造函數(shù)來實現(xiàn)對實例屬性的繼承。
原型式繼承
原型式繼承:是借助原型可以基于已有的對象創(chuàng)建新對象,同時還不必因此創(chuàng)建自定義類型。講到這里必須得提到一個人,道格拉斯·克羅克福德在2006年寫的一篇文章《Prototype inheritance in Javascript》(Javascript中的原型式繼承)中給出了一個方法:
function object(o) { //傳遞一個字面量函數(shù) function F(){} //創(chuàng)建一個構(gòu)造函數(shù) F.prototype = o; //把字面量函數(shù)賦值給構(gòu)造函數(shù)的原型 return new F() //最終返回出實例化的構(gòu)造函數(shù) }
看如下的例子:
function obj(o) { function F (){} F.prototype = o; return new F() } var box = { name: 'ccc', age: 18, family: ['哥哥','姐姐'] } var box1 = obj(box) console.log(box1.name) // --> ccc box1.family.push('妹妹') console.log(box1.family) // --> ["哥哥", "姐姐", "妹妹"] var box2 = obj(box) console.log(box2.family) // --> ["哥哥", "姐姐", "妹妹"]
因為上述的代碼的實現(xiàn)邏輯跟原型鏈繼承很類似,所以里面的引用數(shù)組,即family屬性被共享了。
寄生式繼承
function obj(o) { function F (){} F.prototype = o; return new F() } function create(o){ var clone = obj(o) // 通過調(diào)用函數(shù)創(chuàng)建一個新對象 clone.sayName = function(){ // 以某種方式來增強這個對象 console.log('hi') } return clone // 返回這個對象 } var person = { name: 'ccc', friends: ['aa','bb'] } var anotherPerson = create(person) anotherPerson.sayName() // --> hi
這個例子中的代碼基于person返回一個新對象————anotherPerson。新對象不僅具有person的所有屬性和方法,而且還有自己的sayHi()方法。在主要考慮對象而不是自定義類型和構(gòu)造函數(shù)的情況下,寄生式繼承也是一種有用的模式。使用寄生式繼承來為對象添加函數(shù),會由于不能做到函數(shù)復用而降低效率,這一點與構(gòu)造函數(shù)模式類似。
寄生組合式繼承
前面說過,組合繼承是Javascript最常用的繼承模式,不過,它也有自己的不足。組合繼承最大的問題就是無論什么情況下,都會調(diào)用過兩次超類型構(gòu)造函數(shù):一次是在創(chuàng)建子類型原型的時候,另一次是在子類型構(gòu)造函數(shù)內(nèi)部。沒錯,子類型最終會包含超類型對象的全部實例屬性,但我們不得不在調(diào)用子類型構(gòu)造函數(shù)時重寫這些屬性,再來看一下下面的例子:
function SuperType(name){ this.name = name; this.colors = ['red','black'] } SuperType.prototype.sayName = function (){ console.log(this.name) } function SubType(name, age){ SuperType.call(this, name) // 第二次調(diào)用SuperType this.age = age } SubType.prototype = new SuperType() // 第一次調(diào)用SuperType SubType.prototype.constructor = SubType SubType.prototype.sayAge = function (){ console.log(this.age) }
第一次調(diào)用SuperType構(gòu)造函數(shù)時,SubType.prototype會得到兩個屬性:name和colors。他們都是SuperType的實例屬性,只不過現(xiàn)在位于SubType的原型中。當調(diào)用SubType構(gòu)造函數(shù)時,又會調(diào)用一次SuperType構(gòu)造函數(shù),這個一次又在新對象上創(chuàng)建了實例屬性name和colors。于是,這兩個屬性就屏蔽了原型中的兩個同名屬性。即有兩組name和colors屬性:一組在實例上,一組在原型上。這就是調(diào)用兩次SuperType構(gòu)造函數(shù)的結(jié)果。解決這個問題的方法就是————寄生組合式繼承。
所謂寄生組合式繼承,即通過借用構(gòu)造函數(shù)來繼承屬性,通過原型鏈的混成形式來繼承方法。其背后的基本思路是:不必為了制定子類型的原型而調(diào)用超類型的構(gòu)造函數(shù),我們所需要的無非就是超類型原型的一個副本而已。本質(zhì)上,就是使用寄生式繼承來繼承超類型的原型,然后再將結(jié)果指定給子類型的原型。寄生組合式繼承的基本模式如下:
function object(o) { function F (){} F.prototype = o; return new F() } function inheritPtototype(subType, superType){ var prototype = object(superType.prototype) // 創(chuàng)建對象 prototype.constructor = subType // 增強對象 subType.prototype = prototype // 指定對象 } function SuperType(name){ this.name = name this.colors = ['red', 'white'] } SuperType.prototype.sayName = function(){ console.log(this.name) } function SubType(name,age){ SuperType.call(this,name) this.age = age } inheritPtototype(SubType, SuperType) SubType.prototype.sayAge = function(){ console.log(this.age) } var instance = new SubType('ccc', 18) instance.sayName() // --> ccc instance.sayAge() // --> 18 console.log(instance)
控制臺打印出的結(jié)構(gòu):
詳細的圖解:
這個例子的高效率提現(xiàn)在它值調(diào)用了一次SuperType構(gòu)造函數(shù),并且因此避免了在SubType.prototype上面創(chuàng)建不必要的、多余的屬性。與此同時,原型鏈還能保持不變;因此,還能夠正常使用instanceof和isPrototypeOf()。這也是很多大廠用的繼承方式。
以上就是js中實現(xiàn)繼承的五種方法的詳細內(nèi)容,更多關于js 實現(xiàn)繼承的資料請關注腳本之家其它相關文章!
相關文章
JavaScript基于自定義函數(shù)判斷變量類型的實現(xiàn)方法
這篇文章主要介紹了JavaScript基于自定義函數(shù)判斷變量類型的實現(xiàn)方法,結(jié)合實例形式分析了javascript判斷變量類型的自定義函數(shù)定義與使用方法,并針對不同瀏覽器給出了相關的分析與說明,需要的朋友可以參考下2016-11-11使用openSpeDiv方法實現(xiàn)Ecshop登錄彈窗框效果
在ECSHOP的目錄/JS/common.js中有一個openSpeDiv方法是實現(xiàn)ECSHOP的彈窗效果的。接下來通過本文給大家分享使用openSpeDiv方法實現(xiàn)Ecshop登錄彈窗框效果,需要的朋友參考下2017-03-03javascript在網(wǎng)頁中實現(xiàn)讀取剪貼板粘貼截圖功能
這篇文章主要介紹了在網(wǎng)頁中實現(xiàn)讀取剪貼板粘貼截圖功能,即可以把剪貼板的截圖Ctrl+V粘貼到網(wǎng)頁的一個輸入框中,例如QQ截圖、旺旺截圖或者其它截圖軟件,需要的朋友可以參考下2014-06-06JavaScript在IE和Firefox瀏覽器下的7個差異兼容寫法小結(jié)
盡管那需要用長串的、沉悶的不同分支代碼來應付不同瀏覽器的日子已經(jīng)過去,偶爾還是有必要做一些簡單的區(qū)分和目標檢測來確保某塊代碼能在用戶的機器上正常運行。2010-06-06利用進制轉(zhuǎn)換壓縮數(shù)字函數(shù)分享
本文主要介紹了進制轉(zhuǎn)換函數(shù),用于壓縮數(shù)字,比如Date.now()這樣的長數(shù)字,用62進制表示,就更短,大家參考使用吧2014-01-01Nuxt3?布局layouts和NuxtLayout的使用詳解
layouts是Nuxt3提供的一種方便開發(fā)者快速實現(xiàn)自定義布局的約定,是基于Vue3的一個開發(fā)框架,基于服務器端渲染SSR,可以更加方便的用于Vue的SEO優(yōu)化,這篇文章主要介紹了Nuxt3?布局layouts和NuxtLayout的使用,需要的朋友可以參考下2023-04-04javascript 操作Word和Excel的實現(xiàn)代碼
javascript 操作Word和Excel的實現(xiàn)代碼, 需要的朋友可以參考下。2009-10-10