在javascript中,typeof 和 instanceof 是用来判断数据类型比较通用的两个方法,但这两种方式并不能完全解决实际中遇到的问题。因此,这篇文章的目的是通过对这两个方法介绍来分析其存在的问题和不足,并提供一个比较简单的优化方案。
typeof
typeof 返回一个表达式的数据类型的字符串,返回结果为javascript中的基本数据类型,包括:number、boolean、string、object、undefined、function等6种数据类型。
typeof 100; //number typeof (1==1); //boolean typeof 'onepixel'; //string typeof {} ; //object typeof onepixel; // undefined typeof parseInt; // function typeof ;//object typeof new Date; //object
可以看出,typeof 可以准确的判断除object以外的基础数据类型,但不能区分object类型的具体类型,比如 Array 、Date 以及自定义类。
instanceof
instanceof 本意是用来判断 A 是否为 B 的实例对象,表达式为:A instanceof B,如果A是B的实例,则返回true,否则返回false。 在这里需要特别注意的是:instanceof检测的是原型,那它是怎么检测的呢,我们用一段伪代码来模拟其内部执行过程:
instanceof (A,B) = { var L = A.__proto__; var R = B.prototype; if(L === R) { //A的内部属性__proto__指向B的原型对象 return true; } return false; }
从上述过程可以看出,当 A 的 __proto__ 指向 B 的 prototype 时,就认为A就是B的实例对象,我们再来看几个例子:
instanceof Array; //true {} instanceof Object;//true new Date instanceof Date;//true function Person{}; new Person instanceof Person; instanceof Object; //true new Date instanceof Object;//true new Person instanceof Object;//true
从上面的例子中,我们发现,虽然 instanceof 能够正确判断 是Array的实例对象,但 instanceof 认为 也是Object的实例对象,为什么呢? 这还需要从JS的原型链说起,我们首先来分析一下、Array、Object 三者之间的关系: 从instanceof能够判断出 .__proto__ 指向 Array.prototype, 而实际上 Array.prototype.__proto__ 指向了Object.prototype,
Object.prototype.__proto__ 指向了null,标志着原型链的结束。(ps:关于JS原型链请阅读:浅谈javascript原型和原型链) 因此,、Array、Object就形成了一条原型链:
从原型链可以看出, 的 __proto__ 最终指向了Object.prototype,因此,JS认为 也是Object的实例。当然,类似的new Date、new Person 也会形成这样一条原型链,因此,用 instanceof 只能够用来判断已知的数据类型,比如: instanceof Array , 而不能获取一个对象的具体数据类型。
优化方案
对于这个问题,在阅读jQuery源码时,发现 jQuery 实现了一个较好的解决方案来获取数据类型,由于源码之间存在相互调用不便于阅读和理解,因此,我按照其思路进行了整理和封装,代码如下:
(function{ var class2type = {}; var typeList = "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ); typeList.eachEach(function(item){ class2type[ "[object " + item + "]" ] = item.toLowerCase; } return { getObjType:function(obj) { if ( obj == null ) { return obj + ""; } if(typeof obj === "object" || typeof obj === "function"){ return class2type[ toString.call( obj ) ] || "object" }else { return typeof obj; } } } })
代码仅供参考,如有不同见解,欢迎交流!
by @ 一像素 2016.01