Stories

Detail Return Return

ES5、ES6 如何實現繼承 - Stories Detail

完整高頻題庫倉庫地址:https://github.com/hzfe/aweso...

完整高頻題庫閲讀地址:https://febook.hzfe.org/

相關問題

  • 關於 ES5 和 ES6 的繼承問題
  • 原型鏈概念

回答關鍵點

原型鏈繼承 構造函數繼承 ES6 類繼承

繼承是指子類型具備父類型的屬性和行為,使代碼得以複用,做到設計上的分離。JavaScript 中的繼承主要通過原型鏈和構造函數來實現。常見的繼承方法有:ES6 中 class 的繼承、原型鏈繼承、寄生組合式繼承等。

知識點深入

1. 原型鏈

原型鏈的本質是拓展原型搜索機制。每個實例對象都有一個私有屬性 \_\_proto\_\_。該屬性指向它的構造函數的原型對象 prototype。該原型對象的 \_\_proto\_\_ 也可以指向其他構造函數的 prototype。依次層層向上,直到一個對象的 \_\_proto\_\_ 指向 null。根據定義,null 沒有原型,並作為這個原型鏈中的最後一個環節。

當試圖訪問一個對象的屬性時,它不僅僅在該對象上搜尋,還會搜尋該對象的原型,以及該對象的原型的原型,依次層層向上搜索,直到找到一個名字匹配的屬性或直到這個鏈表結束(Object.prototype.__proto__ === null)。

2. 原型鏈繼承

原型鏈繼承的思想:一個引用類型繼承另一個引用類型的屬性和方法

function SuperType() {
  this.b = [1, 2, 3];
}

function SubType() {}

SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;

var sub1 = new SubType();
var sub2 = new SubType();

// 這裏對引用類型的數據進行操作
sub1.b.push(4);

console.log(sub1.b); // [1,2,3,4]
console.log(sub2.b); // [1,2,3,4]
console.log(sub1 instanceof SuperType); // true

優點:

  1. 父類新增原型方法/原型屬性,子類都能訪問到。
  2. 簡單、易於實現。

缺點:

  1. 無法實現多繼承。
  2. 由於原型中的引用值被共享,導致實例上的修改會直接影響到原型。
  3. 創建子類實例時,無法向父類構造函數傳參。

3. 構造函數繼承

構造函數繼承的思想:子類型構造函數中調用父類的構造函數,使所有需要繼承的屬性都定義在實例對象上

function SuperType(name) {
  this.name = name;
  this.b = [1, 2, 3];
}

SuperType.prototype.say = function () {
  console.log("HZFE");
};

function SubType(name) {
  SuperType.call(this, name);
}

var sub1 = new SubType();
var sub2 = new SubType();

// 傳遞參數
var sub3 = new SubType("Hzfe");

sub1.say(); // 使用構造函數繼承並沒有訪問到原型鏈,say 方法不能調用

console.log(sub3.name); // Hzfe

sub1.b.push(4);

// 解決了原型鏈繼承中子類實例共享父類引用屬性的問題
console.log(sub1.b); // [1,2,3,4]
console.log(sub2.b); // [1,2,3]
console.log(sub1 instanceof SuperType); // false

優點:

  1. 解決了原型鏈繼承中子類實例共享父類引用屬性的問題。
  2. 可以在子類型構造函數中向父類構造函數傳遞參數。
  3. 可以實現多繼承(call 多個父類對象)。

缺點:

  1. 實例並不是父類的實例,只是子類的實例。
  2. 只能繼承父類的實例屬性和方法,不能繼承原型屬性和方法。
  3. 無法實現函數複用,每個子類都有父類實例函數的副本,影響性能。

4. 組合繼承(偽經典繼承)

組合繼承的思想:使用原型鏈實現對原型屬性和方法的繼承,借用構造函數實現對實例屬性的繼承

function SuperType(name) {
  this.name = name;
  this.a = "HZFE";
  this.b = [1, 2, 3, 4];
}

SuperType.prototype.say = function () {
  console.log("HZFE");
};

function SubType(name) {
  SuperType.call(this, name); // 第二次調用 SuperType
}

SubType.prototype = new SuperType(); // 第一次調用 SuperType
SubType.prototype.constructor = SubType;

優點:

  1. 可以繼承實例屬性/方法,也可以繼承原型屬性/方法。
  2. 不存在引用屬性共享問題。
  3. 可傳參
  4. 函數可複用

缺點:

  1. 調用了兩次父類構造函數(耗內存),生成了兩份實例。

5. 寄生組合式繼承

寄生組合式繼承的思想:借用構造函數來繼承屬性,使用混合式原型鏈繼承方法

// 在函數內部,第一步創建父類原型的一個副本,第二部是為創建的副本添加 constructor 屬性,
// 從而彌補因重寫而失去的默認的 constructor 屬性。最後一步,將新創建的對象(即副本)賦值給予類型的原型。
function inheritPrototype(subType, superType) {
  var prototype = Object.create(superType.prototype); // 創建對象
  prototype.constructor = subType; // 增強對象
  subType.prototype = prototype; // 指定對象
}

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

SuperType.prototype.sayName = function () {
  console.log(this.name);
};

function SubType(name, num) {
  SuperType.call(this, name);
  this.num = num;
}

inheritPrototype(SubType, SuperType);

SubType.prototype.sayNum = function () {
  console.log(this.num);
};

優點:

  1. 只調用了一次 SuperType 構造函數,避免了在 SubType.prototype 上創建不必要的屬性。
  2. 能夠正常使用 instanceof 和 isPrototypeOf()。

缺點:

  1. 實現較為複雜

6. ES6 中 class 的繼承

ES6 中引入了 class 關鍵字, class 可以通過 extends 關鍵字實現繼承,還可以通過 static 關鍵字定義類的靜態方法,這比 ES5 的通過修改原型鏈實現繼承,要清晰和方便很多。需要注意的是:class 關鍵字只是原型的語法糖, JavaScript 繼承仍然是基於原型實現的。

class Pet {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  showName() {
    console.log("調用父類的方法");
    console.log(this.name, this.age);
  }
}

// 定義一個子類
class Dog extends Pet {
  constructor(name, age, color) {
    super(name, age); // 通過 super 調用父類的構造方法
    this.color = color;
  }

  showName() {
    console.log("調用子類的方法");
    console.log(this.name, this.age, this.color);
  }
}

優點:

  1. 清晰方便

缺點:

  1. 不是所有的瀏覽器都支持 class。

參考資料

  1. JS 實現繼承的幾種方式
  2. 阮一峯 ES6 入門之 class 的繼承
  3. 《JavaScript 高級程序設計》
  4. 《你不知道的 JavaScript》
user avatar toopoo Avatar zaotalk Avatar nihaojob Avatar chongdianqishi Avatar longlong688 Avatar banana_god Avatar Dream-new Avatar zero_dev Avatar dunizb Avatar jiavan Avatar febobo Avatar woniuseo Avatar
Favorites 129 users favorite the story!
Favorites

Add a new Comments

Some HTML is okay.