instanceof — JavaScript| 為了瞭解原理,那就來實作一個 instanceof 吧!

Leo Chiu
手寫筆記
Published in
6 min readSep 5, 2020

--

前言

在 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() 做了以下幾件事情:

  1. 建立一個空物件 obj,並讓這個 obj 繼承 User
  2. User.apply(obj) 的方式把 obj 做為 this 呼叫 User 這個 constructor。
  3. 回傳 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()

Object.getPrototypeOf() — MDN Web Docs

雖然 __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。

結論

這篇文章我們瞭解了如何實作一個簡易的 instanceofinstanceof 的功能即是它的原理,主要原理是在原型鏈上找符合的 prototype,因此我們使用一個迴圈沿著原型鏈尋找,直到抵達原型鏈的頂端 Object.prototype 為止。

看完 instanceof 的簡易實作是不是覺得沒有想像中複雜,如果原本對於原型鏈有些瞭解,實作一個簡易的 instanceof 應該是不難。但是,在過程中會遇到 JavaScript 原型鏈神奇的設計,像是我們在同場加映中看到的 FunctionObject 互為彼此的 instance。

分享就到這邊,如果喜歡我的文章可以幫我拍個幾下手,在閱讀文章時如果有遇到什麼問題,或是有什麼建議,都歡迎留言告訴我,謝謝。 😃

--

--

Leo Chiu
手寫筆記

每天進步一點點,在終點遇見更好的自己。 Instragram 小帳:@leo.web.dev