# 再戰原型鏈 prototype chain 為什麼會說再呢? 之前有照著老師的文章也寫了兩篇,但是內容跟老師的有 87% 一樣,只是練習一下寫文章的感覺而已。 這次再稍微深入一點點(真的只有一點點),做了些筆記。 ## prototype - **只有 function 才有 `prototype` 屬性** - 當創建一個 function,JavaScript 會自動幫這個 function 添加 `prototype` 屬性,值是一個有 constructor 的**物件**(註一) - 當這個 function 被當作建構函數(constructor)調用(就是用 new 來調用),JavaScript 會創建該 constructor 的實例(instance) - 這個 instance 會繼承 constructor 的 `prototype` 裡所有屬性跟方法(透過 instance 的 `__proto__` 指向 constructor 的 `prototype`) - `A instanceof B` 就是從 A 的 `__proto__.proto__...` 去找 B 的 `prototype` - 所以原型鏈其實是一連串的 `__proto__` 註一:function 的 `prototype` 的 constructor 就是 function 自己本身。 ## \_\_proto\_\_ JavaScript 每個東西(?)都有 `__proto__` 來標示自己繼承的原型。 ```javascript= const obj = {} const num = 123 const str = '666' console.log(obj.__proto__ === Object.prototype) // true console.log(num.__proto__ === Number.prototype) // true console.log(str.__proto__ === String.prototype) // true ``` ## new 其實當我們 new 了一個新的 instance 時,會發生以下幾件事: 1. 建立一個空白的 JavaScript 物件 2. 新增 `__proto__` 屬性到該新物件,這個屬性會指向建構函式的 `prototype` 物件 3. 把 this 綁定到該新物件,也就是建構函式中的 this 會指向該新物件 4. 如果函式沒有 return 任何東西,就會 return this ## 名詞釐清 - prototype:本質應該就是個一般物件而已(?) - Object - 一般物件:Object literal,就是我們一般在 code 會用 `{}` 包起來然後在裡面放東西的那個物件,他的原型是 `Object.prototype` - 構造函數 Object:原型為 `Function.prototype`,剛好有個東西叫做 `Object.prototype`,但其實 `Object.prototype` 比這個構造函數 Object 還要早出現 - Function - 一般函式:構造函數 Function 的實例,所以原型是 `Function.prototype` - 構造函數 Function:原型為 `Function.prototype` - `Function.prototype`:所有構造函數的原型,也就是所有構造函數的 `__proto__` 皆指向 `Function.prototype` - `Object.prototype`:原型鏈的頂端,prototype 的王者 - `Object.prototype` 跟 `Function.prototype` 是獨立於 `Object` 跟 `Function` 特別的存在,要把他們抽出來看 再來看一張圖,可以幫助釐清這些東西 ![](https://content.evernote.com/shard/s23/sh/ab65497c-cad4-4bd4-a1d5-c75252161220/97a6be759c1d6413/deep/0/) 圖片來源:[理解JavaScript的原型链和继承 (oyanglul.us)](https://blog.oyanglul.us/javascript/understand-prototype.html) 從這張圖來看就簡單多了,可以分成兩大類: 1. `__proto__` 指向 `Function.prototype` 的(建構)函式們 2. `__proto__` 指向 `Object.prototype` 的物件們 ## Function 跟 Object 互為 instance ```javascript= console.log(Function instanceof Object) // true console.log(Object instanceof Function) // true ``` 如果你知道 `instanceof` 的機制,而且了解了上面那些關係,那這個雞生蛋蛋生雞的問題就很簡單了。 `A instanceof B` 就是到 A 的 `__proto__...` 找 `B.prototype` 而已 - Function instanceof Object - `Function.__proto__ === Function.prototype` - `Function.prototype.__proto__ === Object.prototype` - 所以 `Function.__proto__.__proto__ === Object.prototype` - Object instanceof Function - `Object.__proto__ === Function.prototype` ## 從分類來看 ### prototype 只有~~尊爵不凡的~~函式才有 1. Object.prototype - prototype 的王者,所有 prototype 的 `__proto__` 都會指向 `Object.prototype` 3. Function.prototype - 所有(建構)函式的 `__proto__` 都會指向 `Function.prototype` 5. 其他(建構)函式的 prototype - 單純的 JavaScript 物件(?),以 `Function.prototype` 為原型 ### 建構函式 1. JavaScript 原有的建構函式 - `Function`、`Object`、`Array`、`String`…等。 2. 自定義的建構函式 - 自己寫一個 function 當作 constructor,你懂的。 ## 總結 `Object.prototype` -> `Function.prototype` -> `Function`、`Object`、`String` 等其他建構函式 原型鏈聽起來好像會串很長,但其實一個東西的 `__proto__` 會是另一個東西的 `prototype`,而所有 `prototype` 的 `__proto__` 都是 `Object.prototype`,所以頂多就是 `A.__proto__.__proto__ === Object.prototype`,兩個 `__proto__` 而已XD ## 參考資料 - [从__proto__和prototype来深入理解JS对象和原型链 · Issue #9 · creeperyang/blog (github.com)](https://github.com/creeperyang/blog/issues/9) - [理解JavaScript的原型链和继承 (oyanglul.us)](https://blog.oyanglul.us/javascript/understand-prototype.html) ###### tags: `Lidemy-MTR05`