【前端100問】Q7:ES5/ES6 的繼承除了寫法以外還有什麼區別?

寫在前面

此係列來源於開源項目:前端 100 問:能搞懂 80%的請把簡歷給我
爲了備戰 2021 春招
每天一題,督促自己
從多方面多角度總結答案,豐富知識
ES5/ES6 的繼承除了寫法以外還有什麼區別?

正文回答

// ES6
class Super {}
class Sub extends Super {}

const sub = new Sub();

Sub.__proto__ === Super;

子類可以直接通過 __proto__ 尋址到父類。

// ES5
function Super() {}
function Sub() {}

Sub.prototype = new Super();
Sub.prototype.constructor = Sub;

var sub = new Sub();

Sub.__proto__ === Function.prototype;

而通過 ES5 的方式,Sub.__proto__ === Function.prototype

ES5 和 ES6 子類 this 生成順序不同。

ES5 的繼承先生成了子類實例,再調用父類的構造函數修飾子類實例

ES6 的繼承先生成父類實例,再調用子類的構造函數修飾父類實例。

這個差別使得 ES6 可以繼承內置對象。

function MyES5Array() {
  Array.call(this, arguments);
}

// it's useless
const arrayES5 = new MyES5Array(3); // arrayES5: MyES5Array {}

class MyES6Array extends Array {}

// it's ok
const arrayES6 = new MyES6Array(3); // arrayES6: MyES6Array(3) []

因爲 this 生成順序不同,所以需要在 constructor 中,需要使用 super()

擴展知識點

ES5 最常見的兩種繼承:原型鏈繼承、構造函數繼承

  1. 原型鏈繼承
// 定義父類
function Parent(name) {
  this.name = name;
}

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

// 定義子類
function Children() {
  this.age = 24;
}

// 通過Children的prototype屬性和Parent進行關聯繼承

Children.prototype = new Parent("陳先生");

// Children.prototype.constructor === Parent.prototype.constructor = Parent

var test = new Children();

// test.constructor === Children.prototype.constructor === Parent

test.age; // 24
test.getName(); // 陳先生

我們可以發現,整個繼承過程,都是通過原型鏈之間的指向進行委託關聯,直到最後形成了”由構造函數所構造“的結局。

  1. 構造函數繼承
// 定義父類
function Parent(value) {
  this.language = ["javascript", "react", "node.js"];
  this.value = value;
}

// 定義子類
function Children() {
  Parent.apply(this, arguments);
}

const test = new Children(666);

test.language; // ['javascript', 'react', 'node.js']
test.value; // 666

構造繼承關鍵在於,通過在子類的內部調用父類,即通過使用 apply()call()方法可以在將來新創建的對象上獲取父類的成員和方法。

  1. ES6 的繼承
// 定義父類
class Father {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  show() {
    console.log(`我叫:${this.name}, 今年${this.age}歲`);
  }
}

// 通過extends關鍵字實現繼承
class Son extends Father {}

let son = new Son("陳先生", 3000);

son.show(); // 我叫陳先生 今年3000歲

ES6 中新增了 class 關鍵字來定義類,通過保留的關鍵字 extends 實現了繼承。實際上這些關鍵字只是一些語法糖,底層實現還是通過【原型鏈之間的委託關聯】關係實現繼承。

區別於 ES5 的繼承,ES6 的繼承實現在於使用 super 關鍵字調用父類,反觀 ES5 是通過 call 或者 apply 回調方法調用父類。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章