---
# System prepended metadata

title: 再戰原型鏈
tags: [Lidemy-MTR05]

---

# 再戰原型鏈
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`