溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

JavaScript中的繼承方式有哪些

發(fā)布時(shí)間:2021-08-11 14:41:15 來源:億速云 閱讀:114 作者:小新 欄目:web開發(fā)

這篇文章將為大家詳細(xì)講解有關(guān)JavaScript中的繼承方式有哪些,小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。

類式繼承(構(gòu)造函數(shù))

JS中其實(shí)是沒有類的概念的,所謂的類也是模擬出來的。特別是當(dāng)我們是用new 關(guān)鍵字的時(shí)候,就使得“類”的概念就越像其他語言中的類了。類式繼承是在函數(shù)對(duì)象內(nèi)調(diào)用父類的構(gòu)造函數(shù),使得自身獲得父類的方法和屬性。call和apply方法為類式繼承提供了支持。通過改變this的作用環(huán)境,使得子類本身具有父類的各種屬性。

var father = function() {
this.age = 52;
this.say = function() {
alert('hello i am '+ this.name ' and i am '+this.age + 'years old');
}
}
var child = function() {
this.name = 'bill';
father.call(this);
}
var man = new child();
man.say();

 原型繼承

原型繼承在開發(fā)中經(jīng)常用到。它有別于類繼承是因?yàn)槔^承不在對(duì)象本身,而在對(duì)象的原型上(prototype)。每一個(gè)對(duì)象都有原型,在瀏覽器中它體現(xiàn)在一個(gè)隱藏的__proto__屬性上。在一些現(xiàn)代瀏覽器中你可以更改它們。比如在zepto中,就是通過添加zepto的fn對(duì)象到一個(gè)空的數(shù)組的__proto__屬性上去,從而使得該數(shù)組成為一個(gè)zepto對(duì)象并且擁有所有的方法。話說回來,當(dāng)一個(gè)對(duì)象需要調(diào)用某個(gè)方法時(shí),它回去最近的原型上查找該方法,如果沒有找到,它會(huì)再次往下繼續(xù)查找。這樣逐級(jí)查找,一直找到了要找的方法。 這些查找的原型構(gòu)成了該對(duì)象的原型鏈條。原型最后指向的是null。我們說的原型繼承,就是將父對(duì)像的方法給子類的原型。子類的構(gòu)造函數(shù)中不擁有這些方法和屬性。

var father = function() {
}
father.prototype.a = function() {
}
var child = function(){}
//開始繼承
child.prototype = new father();
var man = new child();
man.a();

可以看到第七行實(shí)現(xiàn)了原型繼承。很多人并不陌生這種方式。通過在瀏覽器中打印man我們就可以查看各個(gè)原型的繼承關(guān)系。

JavaScript中的繼承方式有哪些

可以看到逐級(jí)的關(guān)系child->object(father實(shí)例化的對(duì)象)->father。child是通過中間層繼承了father的原型上的東西的。但是為什么中間還有一層object呢, 為什么不把child.prototype = father.prototype。 答案是如果這樣做child和father就沒有區(qū)別了。大家應(yīng)該還記得在prototype中有個(gè)constructor屬性,指向的是構(gòu)造函數(shù)。按照正常的情況我們要把constructor的值改回來指向child的構(gòu)造函數(shù)。但如果直接把father.prototype賦值給child.prototype,那么constructor應(yīng)該指向誰呢?所以很顯然只能通過中間層才能使得child和father保持為獨(dú)立的對(duì)象。

類式繼承和原型繼承的對(duì)比

構(gòu)造函數(shù)(類)式繼承

首先,構(gòu)造函數(shù)繼承的方法都會(huì)存在父對(duì)象之中,每一次實(shí)例,都會(huì)將funciton保存在內(nèi)存中,這樣的做法毫無以為會(huì)帶來性能上的問題。

其次,類式繼承是不可變的。無法復(fù)用,在運(yùn)行時(shí),無法修改或者添加新的方法,這種方式是一種固步自封的死方法。實(shí)踐中很少單純使用。

原型繼承

優(yōu)點(diǎn):

原型鏈可改變:原型鏈上的父類可替換可擴(kuò)展

可以通過改變?cè)玩溄佣鴮?duì)子類進(jìn)行修改的。另外就是類式繼承不支持多重繼承,而對(duì)于原型繼承來說,你只需要寫好extend對(duì)對(duì)象進(jìn)行擴(kuò)展即可。

但是原型鏈繼承也有2個(gè)問題。

第一,包含引用類型值的原型屬性會(huì)被所有實(shí)例共享(可以這樣理解:執(zhí)行sub1.arr.push(2);先對(duì)sub1進(jìn)行屬性查找,找遍了實(shí)例屬性(在本例中沒有實(shí)例屬性),沒找到,就開始順著原型鏈向上找,拿到了sub1的原型對(duì)象,一搜身,發(fā)現(xiàn)有arr屬性。于是給arr末尾插入了2,所以sub2.arr也變了)。

第二,在創(chuàng)建子類型的實(shí)例時(shí),不能向超類型的構(gòu)造函數(shù)中傳遞參數(shù)。(實(shí)際上,應(yīng)該說沒有辦法在不影響所有對(duì)象實(shí)例的情況下,給超類型的構(gòu)造函數(shù)傳遞參數(shù))實(shí)踐中很少單純使用原型鏈。

function Super(){
this.val = 1;
this.arr = [1];
}
function Sub(){
// ...
}
Sub.prototype = new Super(); // 核心
var sub1 = new Sub();
var sub2 = new Sub();
sub1.val = 2;
sub1.arr.push(2);
alert(sub1.val); // 2
alert(sub2.val); // 1
alert(sub1.arr); // 1, 2
alert(sub2.arr); // 1, 2

總結(jié):

類式繼承在實(shí)例化時(shí),父類可傳參,不能復(fù)用(父類不可變,每一次實(shí)例都會(huì)將父類內(nèi)容保存在內(nèi)存中)

原型繼承在實(shí)例化時(shí),父類不可傳參,可以復(fù)用(原型鏈可改變(父類可替換可擴(kuò)展),父類不會(huì)保存在內(nèi)存中,而是順著原型鏈查找,但是結(jié)果是原型屬性會(huì)被所有實(shí)例共享(尤其影響引用類型值))

組合繼承(最常用)

組合繼承將原型鏈和借用構(gòu)造函數(shù)的技術(shù)結(jié)合到一起,發(fā)揮兩者之長(zhǎng)的一種繼承模式。

思路是使用原型鏈實(shí)現(xiàn)對(duì)原型屬性和方法的繼承,通過借用構(gòu)造函數(shù)實(shí)現(xiàn)對(duì)實(shí)例屬性的繼承。

function SuperType(name){
this.name = name;
this.numbers = [1,2,3];
}
SuperType.prototype.sayName = function(){
console.log(this.name);
}
function SubType(name,age){
SuperType.call(this,name);
this.age = age;
}
SubType.prototype = new SuperType();
SubType.prototype.sayAge = function(){
console.log(this.age);
}
var instance1 = new SubType('aaa',21);
instance1.numbers.push(666);
console.log(instance1.numbers);
instance1.sayName();
instance1.sayAge();
var instance2 = new SubType('bbb',22);
console.log(instance2.numbers);
instance2.sayName();
instance2.sayAge();

把實(shí)例函數(shù)都放在原型對(duì)象上,通過Sub.prototype = new Super();繼承父類函數(shù),以實(shí)現(xiàn)函數(shù)復(fù)用。

保留借用構(gòu)造函數(shù)方式的優(yōu)點(diǎn),通過Super.call(this);繼承父類的基本屬性和引用屬性,以實(shí)現(xiàn)傳參;

優(yōu)缺點(diǎn)

優(yōu)點(diǎn):

  1. 可傳參

  2. 函數(shù)可復(fù)用

  3. 不存在引用屬性共享問題(圖紙)

缺點(diǎn):

(一點(diǎn)小瑕疵)子類原型上有一份多余的父類實(shí)例屬性,因?yàn)楦割悩?gòu)造函數(shù)被調(diào)用了兩次,生成了兩份,而子類實(shí)例上的那一份屏蔽了子類原型上的。。。又是內(nèi)存浪費(fèi),比剛才情況好點(diǎn),不過確實(shí)是瑕疵。

關(guān)于“JavaScript中的繼承方式有哪些”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI