js中實(shí)現(xiàn)繼承的五種方法
借用構(gòu)造函數(shù)
這種技術(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
從中可以看到,繼承來的只有實(shí)例屬性,而原型上的屬性是訪問不到的。這種模式解決了兩個(gè)問題,就是可以傳參,可以繼承,但是沒有原型,就沒有辦法復(fù)用。
組合繼承
function Box(name){
this.name = name
}
Box.prototype.run = function (){
console.log(this.name + '正在運(yùn)行...')
}
function Desk(name){
Box.call(this, name) // 對象冒充
}
Desk.prototype = new Box() // 原型鏈
var desk = new Desk('ccc')
console.log(desk.name) // --> ccc
desk.run() // --> ccc正在運(yùn)行...
這種繼承方式的思路是:用使用原型鏈的方式來實(shí)現(xiàn)對原型屬性和方法的繼承,而通過借用構(gòu)造函數(shù)來實(shí)現(xiàn)對實(shí)例屬性的繼承。
原型式繼承
原型式繼承:是借助原型可以基于已有的對象創(chuàng)建新對象,同時(shí)還不必因此創(chuàng)建自定義類型。講到這里必須得提到一個(gè)人,道格拉斯·克羅克福德在2006年寫的一篇文章《Prototype inheritance in Javascript》(Javascript中的原型式繼承)中給出了一個(gè)方法:
function object(o) { //傳遞一個(gè)字面量函數(shù)
function F(){} //創(chuàng)建一個(gè)構(gòu)造函數(shù)
F.prototype = o; //把字面量函數(shù)賦值給構(gòu)造函數(shù)的原型
return new F() //最終返回出實(shí)例化的構(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) // --> ["哥哥", "姐姐", "妹妹"]
因?yàn)樯鲜龅拇a的實(shí)現(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)建一個(gè)新對象
clone.sayName = function(){ // 以某種方式來增強(qiáng)這個(gè)對象
console.log('hi')
}
return clone // 返回這個(gè)對象
}
var person = {
name: 'ccc',
friends: ['aa','bb']
}
var anotherPerson = create(person)
anotherPerson.sayName() // --> hi
這個(gè)例子中的代碼基于person返回一個(gè)新對象————anotherPerson。新對象不僅具有person的所有屬性和方法,而且還有自己的sayHi()方法。在主要考慮對象而不是自定義類型和構(gòu)造函數(shù)的情況下,寄生式繼承也是一種有用的模式。使用寄生式繼承來為對象添加函數(shù),會由于不能做到函數(shù)復(fù)用而降低效率,這一點(diǎn)與構(gòu)造函數(shù)模式類似。
寄生組合式繼承
前面說過,組合繼承是Javascript最常用的繼承模式,不過,它也有自己的不足。組合繼承最大的問題就是無論什么情況下,都會調(diào)用過兩次超類型構(gòu)造函數(shù):一次是在創(chuàng)建子類型原型的時(shí)候,另一次是在子類型構(gòu)造函數(shù)內(nèi)部。沒錯(cuò),子類型最終會包含超類型對象的全部實(shí)例屬性,但我們不得不在調(diào)用子類型構(gòu)造函數(shù)時(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ù)時(shí),SubType.prototype會得到兩個(gè)屬性:name和colors。他們都是SuperType的實(shí)例屬性,只不過現(xiàn)在位于SubType的原型中。當(dāng)調(diào)用SubType構(gòu)造函數(shù)時(shí),又會調(diào)用一次SuperType構(gòu)造函數(shù),這個(gè)一次又在新對象上創(chuàng)建了實(shí)例屬性name和colors。于是,這兩個(gè)屬性就屏蔽了原型中的兩個(gè)同名屬性。即有兩組name和colors屬性:一組在實(shí)例上,一組在原型上。這就是調(diào)用兩次SuperType構(gòu)造函數(shù)的結(jié)果。解決這個(gè)問題的方法就是————寄生組合式繼承。
所謂寄生組合式繼承,即通過借用構(gòu)造函數(shù)來繼承屬性,通過原型鏈的混成形式來繼承方法。其背后的基本思路是:不必為了制定子類型的原型而調(diào)用超類型的構(gòu)造函數(shù),我們所需要的無非就是超類型原型的一個(gè)副本而已。本質(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 // 增強(qiáng)對象
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):

詳細(xì)的圖解:

這個(gè)例子的高效率提現(xiàn)在它值調(diào)用了一次SuperType構(gòu)造函數(shù),并且因此避免了在SubType.prototype上面創(chuàng)建不必要的、多余的屬性。與此同時(shí),原型鏈還能保持不變;因此,還能夠正常使用instanceof和isPrototypeOf()。這也是很多大廠用的繼承方式。
以上就是js中實(shí)現(xiàn)繼承的五種方法的詳細(xì)內(nèi)容,更多關(guān)于js 實(shí)現(xiàn)繼承的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
不使用jquery實(shí)現(xiàn)js打字效果示例分享
js打字效果示例js打字效果示例,data-period設(shè)置從打字返回刪字的時(shí)間,data-rotate可加減中英文詞語,不用jquery支持2014-01-01
JS自定義函數(shù)實(shí)現(xiàn)時(shí)間戳轉(zhuǎn)換成date的方法示例
這篇文章主要介紹了JS自定義函數(shù)實(shí)現(xiàn)時(shí)間戳轉(zhuǎn)換成date的方法,結(jié)合具體實(shí)例形式分析了javascript時(shí)間戳與日期格式的計(jì)算與轉(zhuǎn)換相關(guān)操作技巧,需要的朋友可以參考下2017-08-08
JS可斷點(diǎn)續(xù)傳文件上傳實(shí)現(xiàn)代碼解析
這篇文章主要介紹了JS可斷點(diǎn)續(xù)傳文件上傳實(shí)現(xiàn)代碼解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07
JS基于Mootools實(shí)現(xiàn)的個(gè)性菜單效果代碼
這篇文章主要介紹了JS基于Mootools實(shí)現(xiàn)的個(gè)性菜單效果代碼,涉及JavaScript頁面元素的遍歷及樣式的動態(tài)操作技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-10-10
一起盤點(diǎn)JavaScript中一些強(qiáng)大的運(yùn)算符
javascript中的運(yùn)算符大多由標(biāo)點(diǎn)符號表示,少數(shù)由關(guān)鍵字表示,它們的語法言簡意賅,它們的數(shù)量卻著實(shí)不少,下面這篇文章主要給大家介紹了關(guān)于JavaScript中一些強(qiáng)大的運(yùn)算符的相關(guān)資料,需要的朋友可以參考下2021-11-11

