前言
我們用上一節的範例來解釋什麼是 原型 (prototype) 與 原型鏈 (prototype chain),然後也不難發現 JavaScript 很多底層的觀念都是鏈狀的。
回顧上一節的 ES5 範例
1 | function dog(name){ |
上一節的內容中,我們知道只要於 dog.prototype 上新增方法,這樣之後透過 new 產生的 dog 物件都具有 sayHello 方法。
以這個例子來說,當我們印出 d 的內容時,可以發現當中有個隱藏的屬性「.__proto__」,也發現寫在 dog.prototype 上的方法在這邊出現了。
甚至會發現怎麼點開了「.proto」裡面還有一個「.proto」?

「.proto」
以這個例子白話的說,意思就是當在變數 d 指向的物件身上找不到對應的方法時,便從「.__proto__」內尋找有沒有對應的方法,聽起來是不是跟之前解釋的 ScopeChain 有點像呢。
1 | ... 省略 ... |
而使用三等號來比較的話,可以得知兩者是一樣的。
當呼叫 d.sayHello() 的過程
1 | ... 省略 ... |
- 檢查變數
d指向的物件屬性內有沒有sayHello? 這個例子沒有。 - 接著找該物件的
__proto__屬性內有沒有sayHello,若有就停止不會繼續往後找下去。
以這個例子來說,在步驟二時就找到了,那如果沒有的情況呢?
還記得上面的一張圖嗎?
怎麼點開了「
.__proto__」裡面還有一個「.__proto__」?
- 如果還是找不到,便繼續往
.__proto__尋找,如d.__proto__.__proto__
此時先抽離這個步驟,從這邊可以觀察出「.__proto__」是一層一層的,而越後面的「.__proto__」就越接近「底」的部分。
而本例中 dog 物件的「.__proto__」下一層就是原始物件的 prototype ,所以下面程式碼為 true
1 | console.log(d.__proto__.__proto__ === Object.prototype); // true |
如何知道是不是已經找到底層了呢?只要輸出為 null 代表上一層就是頂層了。
1 | console.log(d.__proto__.__proto__.__proto__); // null |

回到剛才的步驟
- 如果還是找不到,便會繼續往
.__proto__尋找,直到找到為止 - 如果找到底層了還是沒有,則跳出錯誤訊息。
1
2
3
4
5
6
7
8
9
10function dog(name){
this.name = name;
}
dog.prototype.getName = function(){
return this.name;
}
var d = new dog('abc');
d.sayHello();

整理一下對應的關聯

可以得知這個過程是一層一層逐漸地往下找的,而這個過程被稱之為原型鏈 (prototype chain),其實跟範圍鏈 (scope chain) 有點相似。
這邊也順手觀察一下 dog.__proto__ 是什麼
1 | console.log(dog.__proto__); // ƒ () { \[native code\] } |
因為 dog 本身就是一個函式,出現這樣子是符合預期的。
觀察至此,大部分的疑惑都解開,只剩下
new了,接下來會提到new到底做了些什麼。
知道了這些可以做什麼?
可以進行一些比較有趣的事情,像是我們可以在 String 的原型上增加一個自己寫的方法,這樣之後只要型別屬於 String 就可以使用。
1 | String.prototype.getFirst = function(){ |
