由於寫本文時全部是在編輯器中邊寫程式碼邊寫感想的,所以,全部思想都寫在程式碼註釋裡面了
// 類繼承 //todo.1 extends 關鍵字 class Animal { constructor(name) { this.speed = 0; this.name = name; } run(speed) { this.speed = speed; console.log(`${this.name} runs with speed ${this.speed}`); } } // 如果“派生類”使用constructor函式,則必須在constructor呼叫this之前使用super來呼叫被繼承類的constructor // 如果“派生類”沒有使用constructor函式,則預設會生成一個constructor,程式碼如下 /** * constructor(...args) { * super(...args) * } */ // 為什麼需要super() ? // 因為“派生類(derived constructor)的建構函式與其他函式之間的區別在於其具有特殊的內部屬性[[ConstructorKind]]:derived” // 這個屬性會影響new 的行為; 當通過new執行一個常規函式時,它將建立一個空物件,並將這個空物件賦值給this; // 但是當繼承的constructor執行時,它不會執行此操作,它期望父類的constructor來完成這項工作。因此派生類必須執行super才能執行 // 父類的constructor來完成這項工作,否則this指向的那個物件不會建立,並且程式會報錯! class Rabbit extends Animal { constructor(name, color) { super(name); this.color = color; } } const rabbit = new Rabbit("兔子", "白色"); //todo.2 深入探究內部原理和[[HomeObject]] // 讓我們先來看一個例子。 const animal = { name:'Animal', eat() { console.log('animal'); } } const tiger = { __proto__:animal, name:'tiger', eat() { this.__proto__.eat.call(this); } } const youngTiger = { __proto__:tiger, name:'youngTiger', eat() { this.__proto__.eat.call(this); } } tiger.eat(); // animal // youngTiger.eat(); // RangeError: Maximum call stack size exceeded // 為什麼會報錯?讓我們來深入探究一下 /** * 在youngerTiger.eat中 * this.__proto__.eat.call(this) * 等於 * youngTiger.__proto__.eat.call(this) * 等於 * tiger.eat.call(this) * 在tiger.eat中 * this.__proto__.eat.call(this) * 等於 * youngTiger.__proto__.eat.call(this) * 等於 * tiger.eat.call(this) */ // 解決方案:[[HomeObject]] // 當一個函式被定義為類或者物件方法時,它的 [[HomeObject]] 屬性就成為了該物件。 // 然後 super 使用它來解析(resolve)父原型及其方法。 let plant = { name:'Plant', grow() { console.log(`${this.name} growing`); } } let flower = { __proto__:plant, grow() { super.grow(); } } let greenFlower = { __proto__:flower, grow() { super.grow() } } greenFlower.grow();//Plant growing // [[HomeObject]]內建屬性是被繫結到JavaScript物件上的,“方法”由哪個物件建立,則 // [[HomeObject]]指向哪個物件,並且[[HomeObject]]一旦建立就是不可變的 // 而且只能被super解析。注意:“方法”不是“函式屬性”, // “方法” {method(){}},“函式屬性”{method:function(){}} // 解析,當物件巢狀繼承時,為了避免Maximum call stack size exceeded錯誤, // 我們可以使用super來代替 this.__proto__.method.call(this)方法,前提是 // [[HomeObject]]屬性存在,並且__proto__存在