寫在前面
此係列來源於開源項目:前端 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 最常見的兩種繼承:原型鏈繼承、構造函數繼承
- 原型鏈繼承
// 定義父類
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(); // 陳先生
我們可以發現,整個繼承過程,都是通過原型鏈之間的指向進行委託關聯,直到最後形成了”由構造函數所構造“的結局。
- 構造函數繼承
// 定義父類
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()
方法可以在將來新創建的對象上獲取父類的成員和方法。
- 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
回調方法調用父類。