Fork me on GitHub

typeof、instanceof的实现原理

typeof

参考

typeof操作符返回一个字符串,表示未经计算的操作数的类型。

JavaScript底层在存储变量时,变量的值是由一个表示类型的标签和实际数据值表示的(都是二进制)。

在JavaScript最初的版本中,使用的时32位系统,为了性能考虑使用低位(前三位)存储了变量的类型信息:

  • 000: 对象
  • 001: 整数
  • 010: 浮点数
  • 100: 字符串
  • 110: 布尔

undefinednull的机器码比较特殊:

  • undefined: -2^30
  • null: 全0

typeof会根据值的类型信息返回的对应的字符串,而代表空指针的null的机器码是全0,它的类型标签自然就是000,所以typeof null返回"object"

instanceof

参考

instanceof是一个二元运算符,如a instanceof b,其中a必须是一个合法的JavaScript对象,b必须是一个合法的JavaScript函数。

至于实现原理,用mdn的话来说:instance运算符用于测试构造函数的prototype属性是否出现在对象原型链中的任何位置。

用代码表示它的实现原理:

1
2
3
4
5
6
7
8
9
10
11
12
13
function my_instanceof(obj, constructor) {
let constuctProto = constructor.prototype
while (true) {
if (obj.__protp__ === null) {
// 遍历完对象的原型链
return false
}
if (obj.__proto__ === constuctProto) {
return true
}
obj = obj.__proto__
}
}

下面举几个例子

  • Object instanceof Object === true

    • 右边的Object被看作是一个构造函数

      构造函数的prototype属性是Object.prototype

    • 左边的Object被看作是一个对象,接下来遍历一下这个对象的原型链

      Object是一个构造函数,那么他的构造函数是Function,Object.__proto__ === Function.prototype,而Function.prototype又是一个普通的对象,他的构造函数是Object
      ,即Object.__proto__.__proto__ === Object.prototype,现在找到构造函数的prototype属性出现在对象原型链了。

两个方法的比较

以上,当我们需要判断变量类型的时候,如果是基本数据类型,可以用typeof,不过需要注意null这个特殊情况。instanceof主要是判断对象的原型链上有没有测试构造函数的prototype属性,偏向寻找构造原型。要想更精确地判断对象实例的类型时,可以采用Object.prototype.toString.call方法

undefined