前言
在 JavaScript 的世界中,要生成一個物件仰賴的都是 constructor,藉由 new
operator 生成 constructor 的 instance。我們先來看一個簡單的例子,首先建立一個 User
,這個 User
便是一個 constructor,然後利用 new
operator 建構 User
的 instance。
有時候我們可能會需要檢測一個 constructor 的 prototype
是否存在於另一個物件的原型鏈 (Prototype Chain)上,就會用到 instanceof
這個指令。
peter
理所當然是 User
的 instance,看起來很像沒什麼問題。
如果我們更深入一點看「為什麼 peter instanceof User
回傳的結果是 true
」,首先我們要先了解 new
operator 運作的過程, new User()
做了以下幾件事情:
- 建立一個空物件
obj
,並讓這個obj
繼承User
。 - 用
User.apply(obj)
的方式把obj
做為this
呼叫User
這個 constructor。 - 回傳
obj
。
透過 new
operator 的執行過程我們了解 obj
繼承了 User
,而 peter
即是 obj
,所以我們可以說 peter
繼承了 User
,因此在 peter
的原型鏈上理應就會有 User.prototype
,因此 peter instanceof User
的結果是 true
。
如果不熟悉 new
operator,想知道執行原理的話,可以看看上週寫的文章。
從零開始實現一個 instanceof
單純看 MDN 對於 instanceof
的說明「 instanceof
用於檢測一個 constructor 的 prototype
是否存在於另一個物件的原型鏈 (Prototype Chain)上」,翻成白話文就是是沿著 obj.__proto__
在原型鏈上尋找是不是存在著 constructor.prototype
。
__proto__
不是一個正規的寫法,而且會影響執行速度,在真實的環境下勁量別使用這個屬性。
Object.getPrototypeOf()
雖然 __proto__
這個屬性不能使用,但是 JavaScript 其實有內建取得一個物件 prototype 的寫法 — Object.getProrotypeof()
,這個函式可以用於取得一個物件的原型。
所以我們就可以利用這個函式拿後物件的原型後,判斷該物件的原型是否 ===
constructor 的 prototype 。
現在你可能對於實作 instanceof
有點想法了,首先我們要知道所有物件的原型頂端都是 Object.prototype
,而且 Object.prototype
的原型是 null
,所以當在原型鏈上找到 null
時,就代表該 constructor 的 prototype
不存在於物件的原型鏈上。
簡單來說,實作 instanceof
可以使用一個迴圈,然後沿著物件的原型往回找,直到遇見 Object.prototype
的原型時就停止。而如果途中有找到原型鏈上的 prototype 與 constructor 的 prototype 嚴格相等,則我們可以說 instanceof
的結果是 true
。反之,如果到了原型鏈的底端頂端仍然沒有找到相同的原型,則結果是 false
。
同場加映 — 奇怪的 JavaScript
JavaScript 是一個恐怖的語言,為什麼這麼說?看過以下程式碼就知道了。這是一個「雞生蛋,蛋生雞」的問題,第一次看到時大概會滿臉黑人問號,為什麼雙方的 prototype
都在對方的原型鏈上。
Object instanceof Function
Object 是一個 constructor,你可以想像有一個 function Object() {}
存在,所以我們才能使用 new Object()
,而所有的 function 又繼承於 Function.prototype
,所以 Object 自然為 Function 的 instance。
Function instanceof Object
Object.prototype
是所有物件的頂端,因此所有的物件最後都會鍊到 Object.prototype
。更具體來說, Function
同樣是一個 constructor,所以 Function 也繼承了 Function.prototype
,而 Function.prototype
又繼承了 Object.prototype
,所以 Function 為 Object 的 instance。
結論
這篇文章我們瞭解了如何實作一個簡易的 instanceof
, instanceof
的功能即是它的原理,主要原理是在原型鏈上找符合的 prototype,因此我們使用一個迴圈沿著原型鏈尋找,直到抵達原型鏈的頂端 Object.prototype
為止。
看完 instanceof
的簡易實作是不是覺得沒有想像中複雜,如果原本對於原型鏈有些瞭解,實作一個簡易的 instanceof
應該是不難。但是,在過程中會遇到 JavaScript 原型鏈神奇的設計,像是我們在同場加映中看到的 Function
與 Object
互為彼此的 instance。
分享就到這邊,如果喜歡我的文章可以幫我拍個幾下手,在閱讀文章時如果有遇到什麼問題,或是有什麼建議,都歡迎留言告訴我,謝謝。 😃