前言
上篇关于类型判断的文章中主要讲了如何用typeof判断基本数据类型与如何用Object.prototype.toString判断引用数据类型,然后在这两者的基础上封装一个既可以用于判断基本数据类型也可用于引用数据类型的type函数。
上面谈到的都是检测自身类型,而无法判断子类型与父类型的从属关系,这篇文章主要就是来解释一下instanceof的用法,以及typeof与instanceof的原理。
instanceof
instanceof用法
instanceof的主要作用是用来怕判断一个实例是否属于某种类型。
let Person= function () {
}
let nicole = new person()
personinstanceof Person // true
当然,instanceof 也可以判断一个实例是否是其父类型或者祖先类型的实例。
let Person = function () {
}
let programmer = function () {
}
programmer.prototype = new Person()
let person = new programmer()
person instanceof person // true
person instanceof programmer // true
这是 instanceof 的用法。不是很复杂,但是我们除了了解它的用法外,还得了解它背后的原理。
instanceof原理
instanceof的原理以一言以蔽之就是只有右边变量的原型在左边变量的原型链上即返回true,否则返回false。
在这里出几道思考题
function Foo() {
}
Object instanceof Object // true
Function instanceof Function // true
Function instanceof Object // true
Foo instanceof Foo // false
Foo instanceof Object // true
Foo instanceof Function // true
其实想要深入了解instanceof的原理就必须了解原型,有需要的朋友可以看我之前写的击穿原型。
这里放张图用来解释上面的题目
解题之前牢记一句话,instanceof的原理是右边变量的原型在左边变量的原型链上,只要记住这句话然后结合上面那张图,所有答案就一目了然了。
Object instanceof Object
Object是什么?构造函数,说直白点,就是函数,所有Object的上一次原型是什么? 当然是Function.prototype啦。左边没向上找一次原型都与右边的原型对比一下,第一次肯定不行,第二次,Function.prototype.__proto__是什么?不记得的朋友们看图哈,没错,是Object.prototype。所有最后的结果当然为true啦。
Function instanceof Function与Function instanceof Object 可以按照上述方法来分析,最终得到的结果是一致的。
Foo instanceof Foo
这个为什么放回false呢?Foo的原型是Function.prototype一值向上也找不到Foo.prototype。所有当然会返回false啦。
手写一个instanceof
function newInstanceOf(leftValue, rightValue) {
//基本数据类型直接返回false
if(typeof left !== 'object' || left === null) return false;
let rightProto = rightValue.prototype; //获取右边变量原型
while (true) {
if (leftValue === null) {
return false; //如果左边变量原型为返回null,直接返回false
}
if (leftValue === rightProto) {
return true; //如果右边变量的原型在左边变量的原型链上,返回true
}
leftValue = Object.getPrototypeOf(leftValue); 如果不等于,继续循环
}
}
typeof原理
不同的对象在底层都表示为二进制,在JS中二进制前三位储存其类型信息。
000: 对象 010: 浮点数 100:字符串 110:布尔 1: 整数 typeof null 会等于object的原因是,null的二进制全为0,那么前(低)三位也是0,所以执行typeof时会返回"object"。
注意:这里的前是从右向左数。
且typeof无法区分Array,Date这些数据类型的原因就因为这些数据类型在底层表示的二进制中的前三位都为0。(在 JS 的最初版本中使用的是 32 位系统,为了性能考虑使用低位存储变量的类型信息)
总结
- 基本数据类型判断用typeof,当然需要注意null这个异类
- 引用数据类型用Object.peototype.toString方法,当然用instanceof也不是也行,不过用不好容易出现错误,比如一个数组,它可以被
instanceof判断为 Object. - 最好的类型判断的方法是封装一个函数,基本数据类型用typeof判断,引用数据类型用Object.prototype.toString判断。
- instanceof主要用于判断实例与构造函数的从属关系