iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 4
0
Modern Web

從技術文章深入學習 JavaScript系列 第 4

Day 04 [原型鍊02]淺談instanceof 和typeof 的實現原理

文章選自

作者:nicole_zhang18970

連接:https://juejin.im/post/6844903613584654344

來源:掘金

typeof

一般被用於判斷一個變量的類型,可判斷七種類型

number, string, object, boolean, function, undefined, symbol

但有一個很麻煩的事情,只能知道那個變量是object不能知道更精確的類型

let s = new String('abc'); 

typeof  s === 'object'  // true

// 還必須靠instanceof
s instanceof String // true

而且還有一個老梗,就是null也會顯示object (上古bug)

typeof null // object 

所以typeof通常只被用來檢查基本類型

附註: 有一個不錯的方法

不錯的方法: Object.prototype.toString.call(element)

可以利用這個做出更精銳的判斷

Object.prototype.toString.call(5) // "[object Number]"

Object.prototype.toString.call('foo') // "[object String]"

Object.prototype.toString.call({foo:'bar'}) // "[object Object]"

Object.prototype.toString.call(['foo','a']) // "[object Array]"

Object.prototype.toString.call(true) // "[object Boolean]"

Object.prototype.toString.call(() => {}) // "[object Function]"

Object.prototype.toString.call(null) // "[object Null]"

Object.prototype.toString.call(undefined) // "[object Undefined]"

Object.prototype.toString.call(Symbol(1)) // "[object Symbol]"

起初的底層原理

參考自 https://2ality.com/2013/10/typeof-null.html

會顯示 typeof null 為 object 這個錯誤源自於 JavaScript 第一個版本。

於此版本中,JavaScript的值以32位元存儲,其中包括了一個小型單位標籤(1~3位),此類型標籤存在32位元的低位,如以下五個。

  • 000:對象
  • 010:浮點數
  • 100:字符串
  • 110:布爾
  • 1:整數

那我們也就知道為啥null會跑出object了,因為null的所有機器碼全部都是0。
之後null的typeof為object從此被納入ECMA規格中,而所有現代引擎皆按照此規格沿用至今(所以引擎內部實現原理不一定還是為此)。

instanceof

在講這個之前請務必先看以下文章,因為要先建立原型鍊的概念,講解也會用該文的概念去解釋

https://ithelp.ithome.com.tw/articles/10235950

有啥用 ?

主要的作用是判斷一個實例是否屬於某種類型 (也可以是父類型或者祖先類型)

// 1.
function Person() {
    ...
}
let nicole = new Person()
nicole instanceof Person // true

// 2.
function Person () {
    ...
}
function Programmer () {
    ...
}
Programmer.prototype = new Person()
let nicole = new Programmer()
nicole instanceof person // true
nicole instanceof Programmer // true

整理出來的偽代碼

其實就是先找右邊的prototype( 因為機器的prototype會等於實例的__ proto __ )

然後跟左邊的p比較如果不相等就再往上找直到取到null 並 return false

代碼:

// 不難就上面提到的概念看一下應該就會懂
function new_instance_of(leftVaule, rightVaule) { 
    let rightProto = rightVaule.prototype; // 取右表达式的 prototype 值
    leftVaule = leftVaule.__proto__; // 取左表达式的__proto__值
    while (true) {
    	if (leftVaule === null) {
            return false;	
        }
        if (leftVaule === rightProto) {
            return true;	
        } 
        leftVaule = leftVaule.__proto__ 
    }
}

範例

既然知道到底再比較甚麼就好辦啦,直接看例子吧
附註:以下需先閱讀D03內容,否則會看不懂

Object instanceof Object

答案:

true

解析:

右邊: Object 的 prototype 是 NO1

左邊: Object的p往上找會有NO1

示意圖:

https://ithelp.ithome.com.tw/upload/images/20200914/20124350lDRI7vrsxG.png

Function instanceof Function

true

解析:

右邊: Function的prototype是NO2

左邊: Function的p往上就是NO2

示意圖:

https://ithelp.ithome.com.tw/upload/images/20200914/20124350Nior4i6b0S.png

Function instanceof Object

答案:

true

解析:

右邊: Object的prototype指向NO1

左邊: Function的p往上找會有NO1

示意圖(因為右邊只需要prototype是啥,所以我在這裡沒畫Object的proto):

https://ithelp.ithome.com.tw/upload/images/20200914/20124350ia6p9SUg2O.png

Foo instanceof Foo

答案:

false

解析:

右邊: Foo.prototype 指向某一個prototype

左邊: 但Foo的p往上找找不到prototype

示意圖:

附註:

​ 因為右邊僅需要找到prototype所以我沒畫Foo.prototype.__ proto __指向誰(NO1),從這張圖可以發現從Foo往上找會直接找到根本找不到 Foo.prototype,因此會返回 false

https://ithelp.ithome.com.tw/upload/images/20200914/2012435008j31YrqRl.png

Foo instanceof Object

答案:

true

解析:

右邊: Object.prototype 指向NO1

左邊: Foo的p往上找找的到NO1

示意圖:

https://ithelp.ithome.com.tw/upload/images/20200914/201243505WGRMxSLJK.png

Foo instanceof Function

答案:

true

解析:

右邊: Function.prototype 指向NO2

左邊: 但Foo的p往上找的到NO2

示意圖:

https://ithelp.ithome.com.tw/upload/images/20200914/201243508EOEHUtYkE.png


上一篇
Day 03 [原型鍊01] JavaScript 世界萬物誕生記
下一篇
Day 05 [this 01] this、apply、call、bind
系列文
從技術文章深入學習 JavaScript29
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
fillano
iT邦超人 1 級 ‧ 2020-09-15 14:44:11

第一篇文章可能很有問題。古往今來的Javascript引擎何其多,而且有許多開放原始碼,最好找的到類型是這樣實做的舉出來做範例...而且JIT並不一定直接把Javascript翻成機器碼,可能是中間表示式,即使翻成機器碼以後也還可能因為最佳化而改變,中間的鴻溝很大。

看更多先前的回應...收起先前的回應...
s95050937 iT邦新手 5 級 ‧ 2020-09-15 20:04:44 檢舉

您好,想請問第一篇文章是指D03那篇嗎?

fillano iT邦超人 1 級 ‧ 2020-09-15 20:07:33 檢舉

https://juejin.im/post/6844903613584654344 講typeof這篇,尤其是「原理」

s95050937 iT邦新手 5 級 ‧ 2020-09-15 20:26:53 檢舉

以下為MDN內容:
https://ithelp.ithome.com.tw/upload/images/20200915/20124350HHpVeQfL5W.jpg
可以看到後面有一個參考來源
該來源連結為以下:
https://2ality.com/2013/10/typeof-null.html
可以閱讀一下,該篇文章原理來源翻譯自此。

fillano iT邦超人 1 級 ‧ 2020-09-15 20:34:34 檢舉

我看過,你要讀懂原作者的意思。他的解釋是說這是第一版的JavaScript實做的bug,然後進入了ECMA-262,變成規格了。現代的Javascript語言會依照規格實做讓他表現起來是這樣,但這已經不是底層的原理。

s95050937 iT邦新手 5 級 ‧ 2020-09-15 21:21:10 檢舉

了解。大至修改了一下,感謝您

我要留言

立即登入留言