理解typeof和instanceof,从原型开始说起
typeof判断类型存在的问题
对于这两个js关键词,一直停留在很浅显的理解上。
直到最近开始刷个大公司的面试题,发现这一知识点出场之高,决心总结一下。
typeof判断类型,截图来自MDN。
问题出现了,当类型为Null和Array和Object时候,均返回“object”,如何区别?
一种常用的检测方法是使用:
Object.prototype.toString.call(obj)
1 | var arr = [12,'aaa'] |
为什么要使用Object原型上的toString方法,而不是直接调用?
因为Array ,function等类型作为Object的实例,都重写了toString方法
1 | arr.toString() //"12,aaa" |
但是使用上面这种方法判断也存在局限性,对于任何对象,返回都是相同的。我们现在的需求是有不同构造函数比如Student,Dog等等,我们new一个实例的时候想判断这个实例是一个Dog还是一个Student,这时候就需要用到instanceof。
instanceof大法好
1 | var Student = function (name,age) { |
要理解instanceof肯定逃不过原型链,祭出原型链大图
(如果还不理解原型链可以参考其他文章,要求能把下面图看懂)
关键点:
首先,js中一切都是对象,函数也是对象
所有的函数都有prototype和proto属性
所有的对象都有proto属性
Object.prototype是所有对象的根
Function.prototype是所有函数的根
Object和Function都是构造函数
instanceof的判断原理很简单,就是在实例的proto链条上寻找,如果有就返回true
通过上面的图也可以理解几个很奇怪的instanceof判断
1 | Function instanceof Function //true |
补充
这两天看书,发现自己对instanceof的使用有个地方还是不清楚
1 | function Person(){} |
一般的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的方式