JavaScript 中的 instanceof 和 typeof

本博客 hjy-xh,转载请申明出处

instanceof

instanceof运算符用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上

当然,instanceof也可以判断一个实例是否是其祖先类型的实例。

1
2
3
4
5
6
7
8
9
10
function Car(make, model, year) {
this.make = make;
this.model = model;
this.year = year;
}
const auto = new Car('Honda', 'Accord', 1998);

console.log(auto instanceof Car); // true

console.log(auto instanceof Object); // true

根据原型和原型链的相关知识,这里进行一个实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

function myInstanceof(obj, target) {
let targetPrototype = target.prototype;
let objPrototype = obj.__proto__;

while(true) {
if(objPrototype === null) {
return false;
}
if(objPrototype === targetPrototype) {
return true;
}
objPrototype = objPrototype.__proto__;
}
}

typeof

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

这里用一张表来总结typeof的使用情况:

类型 结果
Undefined ‘undefined’
Null ‘object’
Boolean ‘boolean’
Number ‘number’
BigInt ‘bigint’
String ‘string’
Symbol ‘symbol’
Function ‘function’
其它任何对象 ‘object’

眼尖的小伙伴肯定发现了该操作符对于null的执行结果有些奇怪,

1
2
// JavaScript 诞生以来便如此
typeof null === 'object'; // true

在JavaScript最初的实现中,底层存储变量的时候,会在变量的机器码的低位1-3位存储其类型信息:

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

由于null代表的空指针(大多数平台下值为0X00, 所有机器码均为0),因此typeof null 也因此返回 'object'

这也是 JavaScript 的历史遗留bug。

从上面的分析看出,在使用typeof来判断变量类型时,需要避免对null的判断。还有一个不错的判断类型的方法,就是Object.prototype.toString:

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

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

Object.prototype.toString.call({food:'cola'}) // "[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]"

参考

浅谈 instanceof 和 typeof 的实现原理

typeof mdn

instanceof mdn