亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

 更新時(shí)間:2023年03月08日 08:56:51   作者:前端技術(shù)棧  
JS的繼承方式在我們面試的時(shí)候經(jīng)常會(huì)被問到,所以深入理解js繼承方式以及它們的優(yōu)缺點(diǎn)是非常有必要的。本文為大家整理了JavaScript中常見的七種繼承及實(shí)現(xiàn),需要的可以參考一下

1. 原型鏈繼承

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

以下是一個(gè)實(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復(fù)制代碼

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

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

  • 簡(jiǎn)單易懂:原型鏈繼承是一種簡(jiǎn)單的繼承方式,易于理解和實(shí)現(xiàn)。
  • 父類方法更新會(huì)自動(dòng)同步到子類實(shí)例:由于子類實(shí)例的原型指向父類實(shí)例,所以父類的方法更新會(huì)自動(dòng)同步到子類實(shí)例中。
  • 可以重用父類方法:由于子類實(shí)例可以訪問父類的原型,因此可以重用父類的方法,從而減少代碼量。

缺點(diǎn):

  • 所有子類實(shí)例共享原型對(duì)象:由于所有子類實(shí)例的原型都指向同一個(gè)對(duì)象,因此一個(gè)實(shí)例對(duì)原型對(duì)象的修改會(huì)影響到其他實(shí)例。
  • 無法向父類構(gòu)造函數(shù)傳遞參數(shù):原型鏈繼承無法向父類構(gòu)造函數(shù)傳遞參數(shù),因此子類實(shí)例無法向父類構(gòu)造函數(shù)傳遞參數(shù),也無法對(duì)父類實(shí)例進(jìn)行初始化。
  • 無法實(shí)現(xiàn)多繼承:由于JavaScript中一個(gè)對(duì)象只能有一個(gè)原型對(duì)象,因此原型鏈繼承無法實(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)系,因此可以避免共享原型對(duì)象帶來的問題。

子類無法重用父類原型對(duì)象上的方法。

以下是一個(gè)借用構(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復(fù)制代碼

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

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

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

  • 可以向父類構(gòu)造函數(shù)傳遞參數(shù):借用構(gòu)造函數(shù)繼承可以向父類構(gòu)造函數(shù)傳遞參數(shù),從而可以對(duì)父類實(shí)例進(jìn)行初始化。
  • 避免了原型對(duì)象共享的問題:由于借用構(gòu)造函數(shù)繼承創(chuàng)建了一個(gè)新的對(duì)象,因此避免了原型對(duì)象共享的問題。
  • 可以實(shí)現(xiàn)多繼承:由于JavaScript中可以在一個(gè)構(gòu)造函數(shù)中調(diào)用多個(gè)構(gòu)造函數(shù),因此可以通過借用構(gòu)造函數(shù)繼承來實(shí)現(xiàn)多繼承。

缺點(diǎn):

  • 無法重用父類方法:由于借用構(gòu)造函數(shù)繼承創(chuàng)建了一個(gè)新的對(duì)象,因此無法重用父類的方法。
  • 父類方法更新不會(huì)自動(dòng)同步到子類實(shí)例:由于借用構(gòu)造函數(shù)繼承創(chuàng)建了一個(gè)新的對(duì)象,因此父類的方法更新不會(huì)自動(dòng)同步到子類實(shí)例中。
  • 無法訪問父類原型上的屬性和方法:由于借用構(gòu)造函數(shù)繼承只繼承了父類的實(shí)例屬性和方法,因此無法訪問父類原型上的屬性和方法。如果需要訪問父類原型上的屬性和方法,仍然需要通過將子類的原型指向父類的實(shí)例來實(shí)現(xiàn)。

3. 組合繼承

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

以下是一個(gè)組合繼承的示例代碼:

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)'復(fù)制代碼

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

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

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

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

  • 父類的構(gòu)造函數(shù)可以傳遞參數(shù),并且不會(huì)影響到其他實(shí)例。
  • 子類實(shí)例可以訪問父類原型對(duì)象上的方法,可以重用父類的方法。
  • 可以實(shí)現(xiàn)多繼承。
  • 實(shí)現(xiàn)簡(jiǎn)單、易于理解。

缺點(diǎn):

  • 子類實(shí)例會(huì)同時(shí)擁有自己的屬性和方法,以及父類的屬性和方法,可能導(dǎo)致內(nèi)存浪費(fèi)和屬性名沖突的問題。
  • 在創(chuàng)建子類實(shí)例時(shí),父類構(gòu)造函數(shù)會(huì)被調(diào)用兩次,可能會(huì)影響性能。

4. 原型式繼承

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

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

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

可以將一個(gè)對(duì)象作為另一個(gè)對(duì)象的原型對(duì)象。

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

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

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

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

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

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

  • 簡(jiǎn)單、易于理解和實(shí)現(xiàn)。
  • 可以基于一個(gè)對(duì)象創(chuàng)建多個(gè)對(duì)象,實(shí)現(xiàn)對(duì)象復(fù)用。

缺點(diǎn):

  • 父對(duì)象的引用屬性會(huì)被所有子對(duì)象共享,因此子對(duì)象的修改會(huì)影響到其他子對(duì)象。
  • 子對(duì)象無法像傳統(tǒng)的類繼承一樣判斷自己是否是父對(duì)象的實(shí)例。
  • 無法實(shí)現(xiàn)多繼承。

5. 寄生式繼承

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

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

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

functioncreateAnimal(type) {
  let animal = {
    type: type,
    sayType: function() {
      console.log('I am a ' + this.type);
    }
  };
  // 基于animal對(duì)象進(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'復(fù)制代碼

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

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

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

  • 簡(jiǎn)單、易于理解和實(shí)現(xiàn)。
  • 可以基于一個(gè)對(duì)象創(chuàng)建多個(gè)對(duì)象,實(shí)現(xiàn)對(duì)象復(fù)用。
  • 可以在不修改原對(duì)象的情況下,對(duì)繼承過程進(jìn)行一些增強(qiáng),例如添加新的屬性和方法。

缺點(diǎn):

  • 父對(duì)象的引用屬性會(huì)被所有子對(duì)象共享,因此子對(duì)象的修改會(huì)影響到其他子對(duì)象。
  • 子對(duì)象無法像傳統(tǒng)的類繼承一樣判斷自己是否是父對(duì)象的實(shí)例。
  • 增強(qiáng)行為可能會(huì)帶來一定的性能開銷。
  • 可能會(huì)導(dǎo)致代碼的可讀性降低。

6. 寄生式組合繼承

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

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

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'復(fù)制代碼

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

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

  • 實(shí)現(xiàn)了屬性和方法的完整繼承。
  • 避免了組合繼承中重復(fù)調(diào)用父類構(gòu)造函數(shù)的問題,提高了性能。
  • 可以在不修改原對(duì)象的情況下,對(duì)繼承過程進(jìn)行一些增強(qiáng),例如添加新的屬性和方法。

缺點(diǎn):

  • 增加了一層包裝函數(shù),可能會(huì)帶來一定的性能開銷。
  • 可能會(huì)導(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ù)和方法。

以下是一個(gè)使用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)建一個(gè)新的Dog對(duì)象
 
dog.sayType(); // 'I am a canine'
dog.sayName(); // 'My name is Fido'復(fù)制代碼

在上面的代碼中,我們首先定義了一個(gè)Animal類,它包含一個(gè)構(gòu)造函數(shù)和一個(gè)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)建一個(gè)新的Dog對(duì)象,并調(diào)用它的方法來測(cè)試?yán)^承是否成功。

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

  • 代碼可讀性高,更易于理解和維護(hù)。
  • 語法簡(jiǎn)潔,可以更快地編寫代碼。
  • 可以使用現(xiàn)代JavaScript特性,如箭頭函數(shù)、解構(gòu)賦值等。

缺點(diǎn):

  • 與ES5及以下版本的JavaScript不兼容。
  • 需要編譯才能運(yùn)行在低版本瀏覽器中。
  • 某些開發(fā)者可能認(rèn)為使用類和繼承違背了JavaScript的本質(zhì)。

總體來說,class繼承是一種非常方便的繼承方式,特別是在面向?qū)ο缶幊讨?,能夠大大?jiǎn)化代碼的編寫和維護(hù)。但在一些特定情況下,其他繼承方式可能更為適合。

以上就是JavaScript中常見的七種繼承及實(shí)現(xiàn)的詳細(xì)內(nèi)容,更多關(guān)于JavaScript繼承的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論