淺談instanceof 和typeof 的實現原理 (轉載)

淺談instanceof 和typeof 的實現原理 (轉載)

學習自(純紀錄自己學了甚麼,非營利)

https://juejin.im/post/6844903613584654344

typeof

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

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

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

1
2
3
4
5
6
let s = new String('abc'); 

typeof s === 'object' // true

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

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

1
typeof null // object

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

附註: 有一個不錯的方法

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Object.prototype.toString.call(1) // "[object Number]"

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

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

Object.prototype.toString.call([1,'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]"

原理

在此之前要先知道,JS在底層儲存變量的時候時候,會在變量的機器碼的低位1-3位存儲其類型信息(二進制)

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

那我們也就知道為啥null會跑出object了,因為null的所有機器碼全部都是0

instanceof

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

https://s95050937.github.io/zhihu02.html#more

這做啥用的

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 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

代碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 不難就上面提到的概念看一下應該就會懂
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__
}
}

範例

既然知道到底再比較甚麼就好辦啦,直接看例子吧

Object instanceof Object

答案:

true

解析:

右邊: Object 的 prototype 是 NO1

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

示意圖:

Function instanceof Function

true

解析:

右邊: Function的prototype是NO2

左邊: Function的p往上就是NO2

示意圖:

Function instanceof Object

答案:

true

解析:

右邊: Object的prototype指向NO1

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

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

Foo instanceof Foo

答案:

false

解析:

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

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

示意圖:

附註:

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

Foo instanceof Object

答案:

true

解析:

右邊: Object.prototype 指向NO1

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

示意圖:

Foo instanceof Function

答案:

true

解析:

右邊: Function.prototype 指向NO2

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

示意圖: