理解typeof和instanceof,从原型开始说起

typeof判断类型存在的问题

对于这两个js关键词,一直停留在很浅显的理解上。
直到最近开始刷个大公司的面试题,发现这一知识点出场之高,决心总结一下。

typeof判断类型,截图来自MDN。
问题出现了,当类型为Null和Array和Object时候,均返回“object”,如何区别?

一种常用的检测方法是使用:
Object.prototype.toString.call(obj)

1
2
var arr = [12,'aaa']
Object.prototype.toString.call(arr) //"[object Array]"

为什么要使用Object原型上的toString方法,而不是直接调用?
因为Array ,function等类型作为Object的实例,都重写了toString方法

1
arr.toString()  //"12,aaa"

但是使用上面这种方法判断也存在局限性,对于任何对象,返回都是相同的。我们现在的需求是有不同构造函数比如Student,Dog等等,我们new一个实例的时候想判断这个实例是一个Dog还是一个Student,这时候就需要用到instanceof。

instanceof大法好

1
2
3
4
5
6
7
8
9
var Student = function (name,age) {
this.name = name
this.age = age
}
Student.prototype.say = function(){
console.log(`i am ${name},and i am ${age} years old!`)
}
var stu = new Student('Tom', 20)
stu instanceof Student //true

要理解instanceof肯定逃不过原型链,祭出原型链大图
(如果还不理解原型链可以参考其他文章,要求能把下面图看懂)

关键点:
首先,js中一切都是对象,函数也是对象
所有的函数都有prototype和proto属性
所有的对象都有proto属性
Object.prototype是所有对象的根
Function.prototype是所有函数的根
Object和Function都是构造函数

instanceof的判断原理很简单,就是在实例的proto链条上寻找,如果有就返回true
通过上面的图也可以理解几个很奇怪的instanceof判断

1
2
3
4
Function instanceof Function  //true
Object instanceof Function //true
Object instanceof Object //true
Function instanceof Object //true

补充

这两天看书,发现自己对instanceof的使用有个地方还是不清楚

1
2
3
4
5
function Person(){}
Person.prototype.dance = function(){}
function Ninja(){}
Ninja.prototype = new Person()
const ninja = new Ninja()

一般的js继承写法,一开始我想的是:
Ninja.prototype被改写成一个Person实例对象了
所以:
ninja instanceof Ninja返回false,
ninja instanceof Person 返回true

但是测试返回的是两个true

到底该如何理解instanceof?
检查右边的函数原型是否存在于操作符左边的对象的原型链上
Ninja.prototype 是否在ninja对象的proto链上

当你实例化时候,const ninja = new Ninja()
判断ninja instanceof Ninja时,就看Ninja.prototype是否在ninja实例的proto链条上
而Ninja.prototype是new Person,在ninja实例的proto链条上,所以就返回true
这样才是正确理解instanceof的方式