再戰原型鏈


Posted by rockyooooooo on 2021-07-30

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__ 來標示自己繼承的原型。

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.prototypeFunction.prototype 是獨立於 ObjectFunction 特別的存在,要把他們抽出來看

再來看一張圖,可以幫助釐清這些東西


圖片來源:理解JavaScript的原型链和继承 (oyanglul.us)

從這張圖來看就簡單多了,可以分成兩大類:

  1. __proto__ 指向 Function.prototype 的(建構)函式們
  2. __proto__ 指向 Object.prototype 的物件們

Function 跟 Object 互為 instance

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
  2. Function.prototype
    • 所有(建構)函式的 __proto__ 都會指向 Function.prototype
  3. 其他(建構)函式的 prototype
    • 單純的 JavaScript 物件(?),以 Function.prototype 為原型

建構函式

  1. JavaScript 原有的建構函式
    • FunctionObjectArrayString…等。
  2. 自定義的建構函式
    • 自己寫一個 function 當作 constructor,你懂的。

總結

Object.prototype -> Function.prototype -> FunctionObjectString 等其他建構函式

參考資料


#javascript







Related Posts

用 Nest.js 開發 API 吧 (六) - TypeORM

用 Nest.js 開發 API 吧 (六) - TypeORM

資料庫型態的選擇以及 cookie

資料庫型態的選擇以及 cookie

一起用 JavaScript 來複習經典排序法吧!

一起用 JavaScript 來複習經典排序法吧!


Comments