溫馨提示×

溫馨提示×

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

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

JavaScript中常見的七種繼承怎么實(shí)現(xiàn)

發(fā)布時(shí)間:2023-03-08 09:20:34 來源:億速云 閱讀:102 作者:iii 欄目:開發(fā)技術(shù)

本篇內(nèi)容主要講解“JavaScript中常見的七種繼承怎么實(shí)現(xiàn)”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“JavaScript中常見的七種繼承怎么實(shí)現(xiàn)”吧!

1. 原型鏈繼承

原型鏈繼承是 JavaScript 中一種基于原型的繼承方式,它通過將一個構(gòu)造函數(shù)的實(shí)例作為另一個構(gòu)造函數(shù)的原型,從而實(shí)現(xiàn)繼承。具體來說,就是在子類的構(gòu)造函數(shù)中通過 Child.prototype = new Parent() 的方式來繼承父類的屬性和方法。

以下是一個實(shí)現(xiàn)原型鏈繼承的示例代碼:

// 定義父類構(gòu)造函數(shù)functionParent(name) {
  this.name = name;
}
 
// 父類原型上的方法Parent.prototype.sayName = function() {
  console.log('My name is ' + this.name);
}
 
// 定義子類構(gòu)造函數(shù)functionChild(name, age) {
  this.age = age;
}
 
// 將子類的原型設(shè)置為父類的實(shí)例Child.prototype = newParent();
 
// 子類原型上的方法Child.prototype.sayAge = function() {
  console.log('I am ' + this.age + ' years old');
}
 
// 創(chuàng)建子類實(shí)例var child = newChild('Tom', 10);
 
// 調(diào)用子類實(shí)例的方法
child.sayName(); // My name is Tom
child.sayAge(); // I am 10 years old

在上面的示例代碼中,我們首先定義了一個父類構(gòu)造函數(shù) Parent,并在其原型上定義了一個方法 sayName。然后我們定義了一個子類構(gòu)造函數(shù) Child,并通過將子類的原型設(shè)置為父類的實(shí)例來實(shí)現(xiàn)繼承。最后我們創(chuàng)建了一個子類實(shí)例 child,并調(diào)用其方法來驗(yàn)證繼承是否成功。

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

  • 簡單易懂:原型鏈繼承是一種簡單的繼承方式,易于理解和實(shí)現(xiàn)。

  • 父類方法更新會自動同步到子類實(shí)例:由于子類實(shí)例的原型指向父類實(shí)例,所以父類的方法更新會自動同步到子類實(shí)例中。

  • 可以重用父類方法:由于子類實(shí)例可以訪問父類的原型,因此可以重用父類的方法,從而減少代碼量。

缺點(diǎn):

  • 所有子類實(shí)例共享原型對象:由于所有子類實(shí)例的原型都指向同一個對象,因此一個實(shí)例對原型對象的修改會影響到其他實(shí)例。

  • 無法向父類構(gòu)造函數(shù)傳遞參數(shù):原型鏈繼承無法向父類構(gòu)造函數(shù)傳遞參數(shù),因此子類實(shí)例無法向父類構(gòu)造函數(shù)傳遞參數(shù),也無法對父類實(shí)例進(jìn)行初始化。

  • 無法實(shí)現(xiàn)多繼承:由于JavaScript中一個對象只能有一個原型對象,因此原型鏈繼承無法實(shí)現(xiàn)多繼承。

2. 借用構(gòu)造函數(shù)繼承

JavaScript中的借用構(gòu)造函數(shù)繼承是一種通過調(diào)用父類構(gòu)造函數(shù)來實(shí)現(xiàn)繼承的方式。這種繼承方式有以下特點(diǎn):

子類實(shí)例擁有了父類構(gòu)造函數(shù)中定義的屬性和方法。

子類實(shí)例與父類實(shí)例之間不存在原型鏈的關(guān)系,因此可以避免共享原型對象帶來的問題。

子類無法重用父類原型對象上的方法。

以下是一個借用構(gòu)造函數(shù)繼承的示例代碼:

functionAnimal(name) {
  this.name = name;
}
 
Animal.prototype.sayName = function() {
  console.log('My name is ' + this.name);
}
 
functionDog(name, age) {
  Animal.call(this, name); // 借用Animal構(gòu)造函數(shù),并將this指向Dog實(shí)例this.age = age;
}
 
let dog1 = newDog('旺財(cái)', 2);
let dog2 = newDog('小白', 1);
 
console.log(dog1.name); // '旺財(cái)'console.log(dog2.age); // 1
dog1.sayName(); // TypeError: dog1.sayName is not a function

在上面的代碼中,Dog類通過調(diào)用Animal構(gòu)造函數(shù)來實(shí)現(xiàn)繼承,從而擁有了Animal類中定義的屬性和方法。由于子類實(shí)例與父類實(shí)例之間不存在原型鏈的關(guān)系,因此修改一個實(shí)例的屬性不會影響到其他實(shí)例。

但是需要注意的是,由于子類實(shí)例無法訪問父類原型對象上的方法,因此在上面的代碼中,dog1實(shí)例調(diào)用sayName()方法會報(bào)錯。如果需要在子類中重用父類原型對象上的方法,可以考慮使用組合繼承或寄生組合式繼承。

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

  • 可以向父類構(gòu)造函數(shù)傳遞參數(shù):借用構(gòu)造函數(shù)繼承可以向父類構(gòu)造函數(shù)傳遞參數(shù),從而可以對父類實(shí)例進(jìn)行初始化。

  • 避免了原型對象共享的問題:由于借用構(gòu)造函數(shù)繼承創(chuàng)建了一個新的對象,因此避免了原型對象共享的問題。

  • 可以實(shí)現(xiàn)多繼承:由于JavaScript中可以在一個構(gòu)造函數(shù)中調(diào)用多個構(gòu)造函數(shù),因此可以通過借用構(gòu)造函數(shù)繼承來實(shí)現(xiàn)多繼承。

缺點(diǎn):

  • 無法重用父類方法:由于借用構(gòu)造函數(shù)繼承創(chuàng)建了一個新的對象,因此無法重用父類的方法。

  • 父類方法更新不會自動同步到子類實(shí)例:由于借用構(gòu)造函數(shù)繼承創(chuàng)建了一個新的對象,因此父類的方法更新不會自動同步到子類實(shí)例中。

  • 無法訪問父類原型上的屬性和方法:由于借用構(gòu)造函數(shù)繼承只繼承了父類的實(shí)例屬性和方法,因此無法訪問父類原型上的屬性和方法。如果需要訪問父類原型上的屬性和方法,仍然需要通過將子類的原型指向父類的實(shí)例來實(shí)現(xiàn)。

3. 組合繼承

JavaScript中的組合繼承是一種結(jié)合借用構(gòu)造函數(shù)和原型鏈繼承的方式,它的核心思想是使用借用構(gòu)造函數(shù)繼承實(shí)例屬性和方法,使用原型鏈繼承共享屬性和方法。

以下是一個組合繼承的示例代碼:

functionAnimal(name) {
  this.name = name;
}
 
Animal.prototype.sayName = function() {
  console.log('My name is ' + this.name);
}
 
functionDog(name, age) {
  Animal.call(this, name); // 借用Animal構(gòu)造函數(shù),并將this指向Dog實(shí)例this.age = age;
}
 
Dog.prototype = newAnimal(); // 原型鏈繼承Animal類的屬性和方法Dog.prototype.constructor = Dog; // 修復(fù)構(gòu)造函數(shù)指向let dog1 = newDog('旺財(cái)', 2);
let dog2 = newDog('小白', 1);
 
console.log(dog1.name); // '旺財(cái)'console.log(dog2.age); // 1
dog1.sayName(); // 'My name is 旺財(cái)'

在上面的代碼中,Dog類通過借用Animal構(gòu)造函數(shù)繼承實(shí)例屬性和方法,通過原型鏈繼承Animal類的屬性和方法。由于子類實(shí)例與父類實(shí)例之間不存在原型鏈的關(guān)系,因此修改一個實(shí)例的屬性不會影響到其他實(shí)例。同時(shí),子類實(shí)例可以重用父類原型對象上的方法。

需要注意的是,由于在上面的代碼中通過Dog.prototype = new Animal()創(chuàng)建了一個新的Animal實(shí)例,因此在創(chuàng)建Dog類時(shí)會調(diào)用兩次Animal構(gòu)造函數(shù),造成了性能上的浪費(fèi)。可以使用寄生組合式繼承來解決這個問題。

具體來說,組合繼承通過將父類的構(gòu)造函數(shù)借用到子類中,從而實(shí)現(xiàn)了父類屬性的繼承,同時(shí)通過將子類的原型設(shè)置為一個新的父類實(shí)例,從而實(shí)現(xiàn)了父類方法的繼承。這種繼承方式具有以下優(yōu)缺點(diǎn):

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

  • 父類的構(gòu)造函數(shù)可以傳遞參數(shù),并且不會影響到其他實(shí)例。

  • 子類實(shí)例可以訪問父類原型對象上的方法,可以重用父類的方法。

  • 可以實(shí)現(xiàn)多繼承。

  • 實(shí)現(xiàn)簡單、易于理解。

缺點(diǎn):

  • 子類實(shí)例會同時(shí)擁有自己的屬性和方法,以及父類的屬性和方法,可能導(dǎo)致內(nèi)存浪費(fèi)和屬性名沖突的問題。

  • 在創(chuàng)建子類實(shí)例時(shí),父類構(gòu)造函數(shù)會被調(diào)用兩次,可能會影響性能。

4. 原型式繼承

JavaScript中的原型式繼承是一種基于已有對象創(chuàng)建新對象的繼承方式,它利用了對象的動態(tài)特性,通過封裝一個函數(shù)來實(shí)現(xiàn)繼承。該函數(shù)接收一個用作新對象原型的對象作為參數(shù),并返回一個新對象,從而實(shí)現(xiàn)了繼承。該方式與借用構(gòu)造函數(shù)繼承類似,但它并不涉及到構(gòu)造函數(shù)和實(shí)例的概念。原型式繼承具有以下特點(diǎn):

基于已有對象創(chuàng)建新對象。

可以使用Object.create()方法實(shí)現(xiàn)。

可以將一個對象作為另一個對象的原型對象。

可以使用原型對象的屬性和方法,但不會影響到原型對象本身。

下面是一個使用原型式繼承的示例代碼:

let animal = {
  type: 'animal',
  sayType: function() {
    console.log('I am a ' + this.type);
  }
};
 
let dog = Object.create(animal); // 使用animal對象作為dog對象的原型
dog.type = 'dog';
 
dog.sayType(); // 'I am a dog'

在上面的代碼中,animal對象擁有一個type屬性和一個sayType方法,dog對象通過使用animal對象作為原型對象來實(shí)現(xiàn)了繼承。因此,dog對象可以使用原型對象的屬性和方法,但并不會影響到原型對象本身。此外,通過給dog對象添加一個type屬性,也可以覆蓋原型對象的type屬性,實(shí)現(xiàn)對父對象屬性的重寫。原型式繼承的優(yōu)點(diǎn)在于可以方便地實(shí)現(xiàn)對象的復(fù)用,但也容易導(dǎo)致對象之間的耦合,不易于維護(hù)。

具體來說,它通過創(chuàng)建一個空對象,并將其原型設(shè)置為一個已有對象,然后向這個空對象中添加屬性和方法來實(shí)現(xiàn)繼承。原型式繼承具有以下優(yōu)缺點(diǎn):

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

  • 簡單、易于理解和實(shí)現(xiàn)。

  • 可以基于一個對象創(chuàng)建多個對象,實(shí)現(xiàn)對象復(fù)用。

缺點(diǎn):

  • 父對象的引用屬性會被所有子對象共享,因此子對象的修改會影響到其他子對象。

  • 子對象無法像傳統(tǒng)的類繼承一樣判斷自己是否是父對象的實(shí)例。

  • 無法實(shí)現(xiàn)多繼承。

5. 寄生式繼承

JavaScript中的寄生式繼承是一種基于已有對象創(chuàng)建新對象的繼承方式,類似于原型式繼承。它的主要區(qū)別是,在新創(chuàng)建的對象上增加一個方法,而這個方法的作用是以某種方式增強(qiáng)對象,然后返回這個對象。這種繼承方式得名于“寄生”,因?yàn)樵鰪?qiáng)對象的方法通常是基于已有的對象進(jìn)行“寄生”而得名。

寄生式繼承的優(yōu)點(diǎn)是可以封裝繼承過程,并且可以向?qū)ο笾刑砑右恍╊~外的屬性和方法。但是和原型式繼承一樣,也存在父對象的引用屬性被所有子對象共享、無法判斷實(shí)例是否是父對象的實(shí)例等問題。

以下是一個使用寄生式繼承的示例代碼:

functioncreateAnimal(type) {
  let animal = {
    type: type,
    sayType: function() {
      console.log('I am a ' + this.type);
    }
  };
  // 基于animal對象進(jìn)行寄生增強(qiáng)let dog = Object.create(animal);
  dog.bark = function() {
    console.log('woof woof');
  };
  return dog;
}
 
let myDog = createAnimal('canine');
myDog.sayType(); // 'I am a canine'
myDog.bark(); // 'woof woof'

在上面的代碼中,我們定義了一個名為createAnimal的函數(shù),用于創(chuàng)建一個繼承自animal對象的新對象。我們在這個新對象上增加了一個bark方法,用于讓對象發(fā)出叫聲。最后,我們返回這個新對象,并將它賦值給myDog變量。通過這樣的方式,我們成功地實(shí)現(xiàn)了寄生式繼承。

具體來說,它在原型式繼承的基礎(chǔ)上增加了一個包裝函數(shù),該函數(shù)用于封裝繼承過程中的一些增強(qiáng)行為。寄生式繼承具有以下優(yōu)缺點(diǎn):

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

  • 簡單、易于理解和實(shí)現(xiàn)。

  • 可以基于一個對象創(chuàng)建多個對象,實(shí)現(xiàn)對象復(fù)用。

  • 可以在不修改原對象的情況下,對繼承過程進(jìn)行一些增強(qiáng),例如添加新的屬性和方法。

缺點(diǎn):

  • 父對象的引用屬性會被所有子對象共享,因此子對象的修改會影響到其他子對象。

  • 子對象無法像傳統(tǒng)的類繼承一樣判斷自己是否是父對象的實(shí)例。

  • 增強(qiáng)行為可能會帶來一定的性能開銷。

  • 可能會導(dǎo)致代碼的可讀性降低。

6. 寄生式組合繼承

JavaScript中的寄生式組合繼承是一種結(jié)合了組合繼承和寄生式繼承的繼承方式。具體來說,它在組合繼承的基礎(chǔ)上,通過寄生式繼承來解決組合繼承中重復(fù)調(diào)用父構(gòu)造函數(shù)的問題。

下面是一個使用寄生式組合繼承的示例代碼:

functionAnimal(name) {
  this.name = name;
  this.type = 'mammal';
}
 
Animal.prototype.sayName = function() {
  console.log('My name is ' + this.name);
};
 
functionDog(name, breed) {
  Animal.call(this, name);
  this.breed = breed;
}
 
// 使用寄生式繼承繼承Animal.prototypeDog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
 
Dog.prototype.sayBreed = function() {
  console.log('I am a ' + this.breed);
};
 
let myDog = newDog('Max', 'Golden Retriever');
myDog.sayName(); // 'My name is Max'
myDog.sayBreed(); // 'I am a Golden Retriever'

在上面的代碼中,我們定義了Animal和Dog兩個構(gòu)造函數(shù),其中Animal構(gòu)造函數(shù)定義了一個name屬性和一個sayName()方法,Dog構(gòu)造函數(shù)在Animal的基礎(chǔ)上添加了一個breed屬性和一個sayBreed()方法。為了實(shí)現(xiàn)寄生式組合繼承,我們使用Object.create()方法基于Animal.prototype創(chuàng)建了一個新的對象,并將其賦值給Dog.prototype,從而使得Dog.prototype的原型鏈指向了Animal.prototype。同時(shí),我們還將Dog.prototype的constructor屬性設(shè)置為Dog,以保證繼承鏈的完整性。最后,我們通過調(diào)用Animal構(gòu)造函數(shù)并將this指向Dog對象,實(shí)現(xiàn)了對Animal屬性的繼承。通過這種方式,我們既避免了組合繼承中重復(fù)調(diào)用父構(gòu)造函數(shù)的問題,又保留了寄生式繼承的靈活性,實(shí)現(xiàn)了一個高效而且靈活的繼承方式。

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

  • 實(shí)現(xiàn)了屬性和方法的完整繼承。

  • 避免了組合繼承中重復(fù)調(diào)用父類構(gòu)造函數(shù)的問題,提高了性能。

  • 可以在不修改原對象的情況下,對繼承過程進(jìn)行一些增強(qiáng),例如添加新的屬性和方法。

缺點(diǎn):

  • 增加了一層包裝函數(shù),可能會帶來一定的性能開銷。

  • 可能會導(dǎo)致代碼的可讀性降低。

7. class繼承

在ES6及以上的版本中,JavaScript引入了class關(guān)鍵字,用于定義類,從而實(shí)現(xiàn)面向?qū)ο缶幊?。class繼承是一種通過類來實(shí)現(xiàn)繼承的方式,它使用extends關(guān)鍵字來指定父類,并通過super關(guān)鍵字來調(diào)用父類的構(gòu)造函數(shù)和方法。

以下是一個使用class繼承的示例代碼:

classAnimal {
  constructor(type) {
    this.type = type;
  }
 
  sayType() {
    console.log('I am a ' + this.type);
  }
}
 
classDogextendsAnimal {
  constructor(type, name) {
    super(type);
    this.name = name;
  }
 
  sayName() {
    console.log('My name is ' + this.name);
  }
}
 
let dog = newDog('canine', 'Fido'); // 創(chuàng)建一個新的Dog對象
 
dog.sayType(); // 'I am a canine'
dog.sayName(); // 'My name is Fido'

在上面的代碼中,我們首先定義了一個Animal類,它包含一個構(gòu)造函數(shù)和一個sayType()方法。然后我們通過extends關(guān)鍵字來指定Dog類的父類為Animal,并在Dog類的構(gòu)造函數(shù)中通過super關(guān)鍵字來調(diào)用Animal構(gòu)造函數(shù),并實(shí)現(xiàn)了sayName()方法。最后,我們創(chuàng)建一個新的Dog對象,并調(diào)用它的方法來測試?yán)^承是否成功。

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

  • 代碼可讀性高,更易于理解和維護(hù)。

  • 語法簡潔,可以更快地編寫代碼。

  • 可以使用現(xiàn)代JavaScript特性,如箭頭函數(shù)、解構(gòu)賦值等。

缺點(diǎn):

  • 與ES5及以下版本的JavaScript不兼容。

  • 需要編譯才能運(yùn)行在低版本瀏覽器中。

  • 某些開發(fā)者可能認(rèn)為使用類和繼承違背了JavaScript的本質(zhì)。

總體來說,class繼承是一種非常方便的繼承方式,特別是在面向?qū)ο缶幊讨校軌虼蟠蠛喕a的編寫和維護(hù)。但在一些特定情況下,其他繼承方式可能更為適合。

到此,相信大家對“JavaScript中常見的七種繼承怎么實(shí)現(xiàn)”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

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

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

AI