最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解JavaScript中8 種不同的繼承實(shí)現(xiàn)方式

 更新時(shí)間:2025年05月03日 08:48:42   作者:北辰alk  
在 JavaScript 中,繼承是實(shí)現(xiàn)代碼復(fù)用和構(gòu)建復(fù)雜對(duì)象關(guān)系的重要機(jī)制,雖然 JavaScript 是一門(mén)基于原型的語(yǔ)言,不像傳統(tǒng)面向?qū)ο笳Z(yǔ)言那樣有類(lèi)的概念,但它提供了多種實(shí)現(xiàn)繼承的方式,本文將詳細(xì)介紹 JavaScript 中 8 種不同的繼承實(shí)現(xiàn)方式,需要的朋友可以參考下

前言

在 JavaScript 中,繼承是實(shí)現(xiàn)代碼復(fù)用和構(gòu)建復(fù)雜對(duì)象關(guān)系的重要機(jī)制。雖然 JavaScript 是一門(mén)基于原型的語(yǔ)言,不像傳統(tǒng)面向?qū)ο笳Z(yǔ)言那樣有類(lèi)的概念,但它提供了多種實(shí)現(xiàn)繼承的方式。本文將詳細(xì)介紹 JavaScript 中 8 種不同的繼承實(shí)現(xiàn)方式,每種方式都會(huì)配有代碼示例和詳細(xì)解釋,最后還會(huì)通過(guò)流程圖比較各種繼承方式的特點(diǎn)。

1. 原型鏈繼承

原型鏈繼承是 JavaScript 中最基本的繼承方式,它利用原型讓一個(gè)引用類(lèi)型繼承另一個(gè)引用類(lèi)型的屬性和方法。

function Parent() {
  this.name = 'Parent';
  this.colors = ['red', 'blue', 'green'];
}

Parent.prototype.getName = function() {
  return this.name;
};

function Child() {
  this.childName = 'Child';
}

// 關(guān)鍵步驟:將Child的原型指向Parent的實(shí)例
Child.prototype = new Parent();

var child1 = new Child();
console.log(child1.getName()); // "Parent"
console.log(child1.childName); // "Child"

// 問(wèn)題:引用類(lèi)型的屬性會(huì)被所有實(shí)例共享
child1.colors.push('black');
var child2 = new Child();
console.log(child2.colors); // ["red", "blue", "green", "black"]

特點(diǎn):

  • 簡(jiǎn)單易實(shí)現(xiàn)
  • 父類(lèi)新增原型方法/屬性,子類(lèi)都能訪問(wèn)到
  • 無(wú)法實(shí)現(xiàn)多繼承
  • 來(lái)自原型對(duì)象的引用屬性被所有實(shí)例共享
  • 創(chuàng)建子類(lèi)實(shí)例時(shí),無(wú)法向父類(lèi)構(gòu)造函數(shù)傳參

2. 構(gòu)造函數(shù)繼承(經(jīng)典繼承)

通過(guò)在子類(lèi)構(gòu)造函數(shù)中調(diào)用父類(lèi)構(gòu)造函數(shù)實(shí)現(xiàn)繼承。

function Parent(name) {
  this.name = name;
  this.colors = ['red', 'blue', 'green'];
}

Parent.prototype.getName = function() {
  return this.name;
};

function Child(name, age) {
  // 關(guān)鍵步驟:在子類(lèi)構(gòu)造函數(shù)中調(diào)用父類(lèi)構(gòu)造函數(shù)
  Parent.call(this, name);
  this.age = age;
}

var child1 = new Child('Tom', 18);
child1.colors.push('black');
console.log(child1.name); // "Tom"
console.log(child1.age); // 18
console.log(child1.colors); // ["red", "blue", "green", "black"]

var child2 = new Child('Jerry', 20);
console.log(child2.colors); // ["red", "blue", "green"]

// 問(wèn)題:無(wú)法繼承父類(lèi)原型上的方法
console.log(child1.getName); // undefined

特點(diǎn):

  • 解決了原型鏈繼承中引用類(lèi)型共享的問(wèn)題
  • 可以在子類(lèi)構(gòu)造函數(shù)中向父類(lèi)構(gòu)造函數(shù)傳參
  • 可以實(shí)現(xiàn)多繼承(call多個(gè)父類(lèi)對(duì)象)
  • 只能繼承父類(lèi)實(shí)例屬性和方法,不能繼承原型屬性和方法
  • 無(wú)法實(shí)現(xiàn)函數(shù)復(fù)用,每個(gè)子類(lèi)都有父類(lèi)實(shí)例函數(shù)的副本,影響性能

3. 組合繼承(最常用)

組合繼承結(jié)合了原型鏈繼承和構(gòu)造函數(shù)繼承的優(yōu)點(diǎn)。

function Parent(name) {
  this.name = name;
  this.colors = ['red', 'blue', 'green'];
}

Parent.prototype.getName = function() {
  return this.name;
};

function Child(name, age) {
  // 構(gòu)造函數(shù)繼承 - 第二次調(diào)用Parent()
  Parent.call(this, name);
  this.age = age;
}

// 原型鏈繼承 - 第一次調(diào)用Parent()
Child.prototype = new Parent();
// 修正constructor指向
Child.prototype.constructor = Child;

Child.prototype.getAge = function() {
  return this.age;
};

var child1 = new Child('Tom', 18);
child1.colors.push('black');
console.log(child1.name); // "Tom"
console.log(child1.age); // 18
console.log(child1.colors); // ["red", "blue", "green", "black"]
console.log(child1.getName()); // "Tom"
console.log(child1.getAge()); // 18

var child2 = new Child('Jerry', 20);
console.log(child2.colors); // ["red", "blue", "green"]
console.log(child2.getName()); // "Jerry"
console.log(child2.getAge()); // 20

特點(diǎn):

  • 融合原型鏈繼承和構(gòu)造函數(shù)繼承的優(yōu)點(diǎn)
  • 既是子類(lèi)的實(shí)例,也是父類(lèi)的實(shí)例
  • 不存在引用屬性共享問(wèn)題
  • 可傳參
  • 函數(shù)可復(fù)用
  • 調(diào)用了兩次父類(lèi)構(gòu)造函數(shù),生成了兩份實(shí)例(子類(lèi)實(shí)例將子類(lèi)原型上的那份屏蔽了)

4. 原型式繼承

借助原型可以基于已有對(duì)象創(chuàng)建新對(duì)象。

function object(o) {
  function F() {}
  F.prototype = o;
  return new F();
}

var person = {
  name: 'Nicholas',
  friends: ['Shelby', 'Court', 'Van']
};

var anotherPerson = object(person);
anotherPerson.name = 'Greg';
anotherPerson.friends.push('Rob');

var yetAnotherPerson = object(person);
yetAnotherPerson.name = 'Linda';
yetAnotherPerson.friends.push('Barbie');

console.log(person.friends); // ["Shelby", "Court", "Van", "Rob", "Barbie"]

ES5 規(guī)范化了原型式繼承,新增了 Object.create() 方法:

var person = {
  name: 'Nicholas',
  friends: ['Shelby', 'Court', 'Van']
};

var anotherPerson = Object.create(person);
anotherPerson.name = 'Greg';
anotherPerson.friends.push('Rob');

var yetAnotherPerson = Object.create(person, {
  name: {
    value: 'Linda'
  }
});
yetAnotherPerson.friends.push('Barbie');

console.log(person.friends); // ["Shelby", "Court", "Van", "Rob", "Barbie"]

特點(diǎn):

  • 不需要單獨(dú)創(chuàng)建構(gòu)造函數(shù)
  • 本質(zhì)是對(duì)給定對(duì)象執(zhí)行淺復(fù)制
  • 適用于不需要單獨(dú)創(chuàng)建構(gòu)造函數(shù),但仍需要在對(duì)象間共享信息的場(chǎng)合
  • 同原型鏈繼承一樣,包含引用類(lèi)型的屬性會(huì)被共享

5. 寄生式繼承

創(chuàng)建一個(gè)僅用于封裝繼承過(guò)程的函數(shù),在函數(shù)內(nèi)部增強(qiáng)對(duì)象。

function createAnother(original) {
  var clone = Object.create(original); // 通過(guò)調(diào)用函數(shù)創(chuàng)建一個(gè)新對(duì)象
  clone.sayHi = function() { // 以某種方式增強(qiáng)這個(gè)對(duì)象
    console.log('Hi');
  };
  return clone; // 返回這個(gè)對(duì)象
}

var person = {
  name: 'Nicholas',
  friends: ['Shelby', 'Court', 'Van']
};

var anotherPerson = createAnother(person);
anotherPerson.sayHi(); // "Hi"

特點(diǎn):

  • 基于原型式繼承
  • 增強(qiáng)了對(duì)象
  • 無(wú)法實(shí)現(xiàn)函數(shù)復(fù)用
  • 同原型式繼承一樣,引用類(lèi)型屬性會(huì)被共享

6. 寄生組合式繼承(最理想)

通過(guò)借用構(gòu)造函數(shù)繼承屬性,通過(guò)原型鏈混成形式繼承方法。

function inheritPrototype(child, parent) {
  var prototype = Object.create(parent.prototype); // 創(chuàng)建父類(lèi)原型的副本
  prototype.constructor = child; // 修正constructor指向
  child.prototype = prototype; // 將副本賦值給子類(lèi)原型
}

function Parent(name) {
  this.name = name;
  this.colors = ['red', 'blue', 'green'];
}

Parent.prototype.getName = function() {
  return this.name;
};

function Child(name, age) {
  Parent.call(this, name);
  this.age = age;
}

// 關(guān)鍵步驟:避免調(diào)用Parent構(gòu)造函數(shù),直接使用父類(lèi)原型
inheritPrototype(Child, Parent);

Child.prototype.getAge = function() {
  return this.age;
};

var child1 = new Child('Tom', 18);
var child2 = new Child('Jerry', 20);

console.log(child1.getName()); // "Tom"
console.log(child1.getAge()); // 18
console.log(child2.getName()); // "Jerry"
console.log(child2.getAge()); // 20

特點(diǎn):

  • 只調(diào)用一次父類(lèi)構(gòu)造函數(shù)
  • 避免在子類(lèi)原型上創(chuàng)建不必要的屬性
  • 原型鏈保持不變
  • 能夠正常使用 instanceof 和 isPrototypeOf
  • 是引用類(lèi)型最理想的繼承方式

7. ES6 Class 繼承

ES6 引入了 class 語(yǔ)法糖,使得繼承更加清晰易讀。

class Parent {
  constructor(name) {
    this.name = name;
    this.colors = ['red', 'blue', 'green'];
  }
  
  getName() {
    return this.name;
  }
}

class Child extends Parent {
  constructor(name, age) {
    super(name); // 調(diào)用父類(lèi)的constructor
    this.age = age;
  }
  
  getAge() {
    return this.age;
  }
}

const child1 = new Child('Tom', 18);
child1.colors.push('black');
console.log(child1.getName()); // "Tom"
console.log(child1.getAge()); // 18
console.log(child1.colors); // ["red", "blue", "green", "black"]

const child2 = new Child('Jerry', 20);
console.log(child2.colors); // ["red", "blue", "green"]

特點(diǎn):

  • 語(yǔ)法更加清晰易讀
  • 底層實(shí)現(xiàn)仍然是基于原型
  • 通過(guò) extends 實(shí)現(xiàn)繼承
  • 子類(lèi)必須在 constructor 中調(diào)用 super(),否則新建實(shí)例時(shí)會(huì)報(bào)錯(cuò)
  • ES6 的繼承機(jī)制完全不同,實(shí)質(zhì)是先創(chuàng)造父類(lèi)的實(shí)例對(duì)象 this(所以必須先調(diào)用 super 方法),然后再用子類(lèi)的構(gòu)造函數(shù)修改 this

8. 混入方式繼承(多繼承)

JavaScript 本身不支持多繼承,但可以通過(guò)混入(Mixin)的方式實(shí)現(xiàn)類(lèi)似功能。

function extend(target, ...sources) {
  sources.forEach(source => {
    for (let key in source) {
      if (source.hasOwnProperty(key)) {
        target[key] = source[key];
      }
    }
    
    // 支持Symbol屬性
    const symbols = Object.getOwnPropertySymbols(source);
    symbols.forEach(symbol => {
      target[symbol] = source[symbol];
    });
  });
  return target;
}

const canEat = {
  eat() {
    console.log(`${this.name} is eating.`);
  }
};

const canWalk = {
  walk() {
    console.log(`${this.name} is walking.`);
  }
};

const canSwim = {
  swim() {
    console.log(`${this.name} is swimming.`);
  }
};

function Person(name) {
  this.name = name;
}

// 將多個(gè)mixin混入Person的原型
extend(Person.prototype, canEat, canWalk);

const person = new Person('John');
person.eat(); // "John is eating."
person.walk(); // "John is walking."
// person.swim(); // 報(bào)錯(cuò),沒(méi)有swim方法

function Fish(name) {
  this.name = name;
}

extend(Fish.prototype, canEat, canSwim);

const fish = new Fish('Nemo');
fish.eat(); // "Nemo is eating."
fish.swim(); // "Nemo is swimming."
// fish.walk(); // 報(bào)錯(cuò),沒(méi)有walk方法

ES6 中可以使用 Object.assign 簡(jiǎn)化混入:

class Person {
  constructor(name) {
    this.name = name;
  }
}

Object.assign(Person.prototype, canEat, canWalk);

class Fish {
  constructor(name) {
    this.name = name;
  }
}

Object.assign(Fish.prototype, canEat, canSwim);

特點(diǎn):

  • 可以實(shí)現(xiàn)類(lèi)似多繼承的功能
  • 靈活性強(qiáng),可以按需組合功能
  • 不是真正的繼承,而是屬性拷貝
  • 可能會(huì)導(dǎo)致命名沖突
  • 無(wú)法使用 instanceof 檢查混入的功能

繼承方式比較流程圖

總結(jié)

JavaScript 提供了多種實(shí)現(xiàn)繼承的方式,每種方式都有其適用場(chǎng)景和優(yōu)缺點(diǎn):

  1. 原型鏈繼承:簡(jiǎn)單但引用類(lèi)型屬性會(huì)被共享
  2. 構(gòu)造函數(shù)繼承:可解決引用共享問(wèn)題但無(wú)法繼承原型方法
  3. 組合繼承:最常用的繼承方式,但會(huì)調(diào)用兩次父類(lèi)構(gòu)造函數(shù)
  4. 原型式繼承:適用于基于已有對(duì)象創(chuàng)建新對(duì)象
  5. 寄生式繼承:增強(qiáng)對(duì)象但無(wú)法函數(shù)復(fù)用
  6. 寄生組合繼承:最理想的繼承方式,高效且完整
  7. ES6 Class繼承:語(yǔ)法糖,底層仍是原型繼承
  8. 混入方式:實(shí)現(xiàn)類(lèi)似多繼承的功能

在實(shí)際開(kāi)發(fā)中,ES6 的 class 語(yǔ)法是最推薦的方式,它語(yǔ)法簡(jiǎn)潔,易于理解,且底層實(shí)現(xiàn)高效。對(duì)于需要兼容舊瀏覽器的項(xiàng)目,可以使用寄生組合式繼承作為替代方案。

理解這些繼承方式的原理和區(qū)別,有助于我們?cè)诓煌瑘?chǎng)景下選擇最合適的實(shí)現(xiàn)方式,寫(xiě)出更優(yōu)雅、高效的 JavaScript 代碼。

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

相關(guān)文章

  • js編寫(xiě)簡(jiǎn)易的計(jì)算器

    js編寫(xiě)簡(jiǎn)易的計(jì)算器

    這篇文章主要為大家詳細(xì)介紹了js編寫(xiě)簡(jiǎn)易的計(jì)算器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-07-07
  • layer彈出框確定前驗(yàn)證:彈出消息框的方法(彈出兩個(gè)layer)

    layer彈出框確定前驗(yàn)證:彈出消息框的方法(彈出兩個(gè)layer)

    今天小編就為大家分享一篇layer彈出框確定前驗(yàn)證:彈出消息框的方法(彈出兩個(gè)layer),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-09-09
  • 個(gè)人網(wǎng)站留言頁(yè)面(前端jQuery編寫(xiě)、后臺(tái)php讀寫(xiě)MySQL)

    個(gè)人網(wǎng)站留言頁(yè)面(前端jQuery編寫(xiě)、后臺(tái)php讀寫(xiě)MySQL)

    這篇文章主要為大家介紹了個(gè)人網(wǎng)站的留言頁(yè)面,前端使用jQuery編寫(xiě)、后臺(tái)利用php簡(jiǎn)單讀寫(xiě)MySQL數(shù)據(jù)庫(kù),感興趣的小伙伴們可以參考一下
    2016-05-05
  • 小程序點(diǎn)擊圖片實(shí)現(xiàn)png轉(zhuǎn)jpg

    小程序點(diǎn)擊圖片實(shí)現(xiàn)png轉(zhuǎn)jpg

    這篇文章主要介紹了小程序點(diǎn)擊圖片實(shí)現(xiàn)png轉(zhuǎn)jpg,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10
  • 如何在javascript 中使用 xmlHttpRequest 發(fā)送 POST 請(qǐng)求

    如何在javascript 中使用 xmlHttpRequest 發(fā)送 POST

    本文將通過(guò)不同的示例解釋如何使用JavaScript代碼在AJAX編程中發(fā)送 XMLHttpRequest post 請(qǐng)求,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2023-07-07
  • 學(xué)習(xí)Bootstrap組件之下拉菜單

    學(xué)習(xí)Bootstrap組件之下拉菜單

    本文介紹了一款基于HTML,CSS,JAVASCRIPT的簡(jiǎn)潔靈活的流行前端框架,需要了解的朋友可以參考下
    2015-07-07
  • 獲取div編輯框,textarea,input text的光標(biāo)位置 兼容IE,F(xiàn)F和Chrome的方法介紹

    獲取div編輯框,textarea,input text的光標(biāo)位置 兼容IE,F(xiàn)F和Chrome的方法介紹

    獲取div編輯框,textarea,input text的光標(biāo)位置 兼容IE,F(xiàn)F和Chrome的方法介紹,有需求的朋友可以參考
    2012-11-11
  • 最新評(píng)論

    横山县| 天等县| 于田县| 宁都县| 大宁县| 丰台区| 临城县| 巢湖市| 镇坪县| 永靖县| 新竹市| 宣武区| 道孚县| 麟游县| 宽城| 乐清市| 杭州市| 绩溪县| 旬阳县| 普格县| 乾安县| 德惠市| 诸城市| 滁州市| 澄迈县| 绍兴县| 卓尼县| 溆浦县| 宁国市| 海门市| 四子王旗| 灵山县| 大余县| 灵川县| 新竹市| 临汾市| 广丰县| 永吉县| 米林县| 南木林县| 清水县|