jquery中有一个方法,$.type(obj)来检测数据类型,用过的前端都应该知道,他能准确的返回一个对象的类型的字符串形式。
今天我们就来分析一下jquery这个方法的实现原理。可能你会说,既然jquery已经提供了这么好的方法了,我们拿来直接用不就得了。确实,拿来主义省事又省事;但如果一直这样的话,你的js水平只能是依赖中jquery的基础上,离开了jquery你什么也干不了了。这并不可怕,现在我们的项目中都在用jquery,甚至移动端我们还有zepto可以替代jquery使用。
现时,已经有好多新兴的前端框架出来了(如angular,react等),他们都可以不依赖jquery,因为他们内部封装了简单jquery库,所谓简单,就是一些常用的功能。而像一些不常用的就抛弃了。这个时候你如果仅仅为了判断一个数据类型而要再引入一个jquery库,就显得有些劳师动众了。而且学习这些原生js的特性,更能提高我们对js的运行机制的了解。
不多说了,开始我们的正题。我们大家都知道的判断js中一个对象的数据类型可以用typeof,是的,没错,他确实有这个能力,但是效果如何呢,我们先定义几个对象。
var num=13;//数字类型 var str="mooshine";//字符串类型 var date=new Date();//日期类型 var bool=true//boolean类型 var obj={name:"jstype"};//对象类型 var unde=undefined;//undefined类型 var arr=[];//数组类型 var fun=function fn(){return "love";};//函数类型 var reg=/^\d+\w$/;//正则表达式对象 var err=new Error(100,"error is occurs");//错误类型 var win=window;//window对象 var div=document.getElementById("div");//dom对象
下面我们采用typeof方法来判断这几个对象的类型。
这里只提供了chrome的截图,中IE和firefox下的运行结果是一致的(已亲测),其他截图就不贴了。
通过运行结果,我们可以看出,typeof可以区分基本类型和函数类型以及undefined,至于date类型,err类型,dom类型,以及null类型和数组,正则类型的都返回的是object,这个我们就无法区分他们到底是什么类型了。
当然还有一个方法是instanceof 来判断一个对象是不是属于某一个类型(date instanceof Date),这样是可以的,可毕竟要做很多的判断,看起来就麻烦。
这个截图是js文档中对于tostring方法的介绍,默认也就是objcet根对象。({}此即使object对象),可以看出object对象可以返回object+具体的类型名称。
那么我们应该怎么让array对象或者Date对象调用object对象的tostring方法呢?
js中有两个方法,一个是call,一个是apply用于改变对象中的this指针。我们把object中的this指针改变为array或者Date对象不就可以了么。
从js文档中对这两个方法的介绍中,我们可以看出这两个方法的功能类似,只是传递参数的方法不同,这里我们的用法不用传递参数,所以,这两个方法都可以用。
var obj={}; var tostring=obj.toString; console.log("number:"+tostring.apply(num)); console.log("string:"+tostring.apply(str)); console.log("date:"+tostring.apply(date)); console.log("boolean:"+tostring.apply(bool)); console.log("obj:"+tostring.apply(obj)); console.log("undefined:"+tostring.apply(unde)); console.log("function:"+tostring.apply(fun)); console.log("err:"+tostring.apply(err)); console.log("window:"+tostring.apply(window)); console.log("dom:"+tostring.apply(dm)); console.log("array:"+tostring.apply(arr)); console.log("null:"+tostring.apply(null));
运行结果如下:
IE8-的运行结果
IE9+,Chrome,Firefox的结果。
可以看到通过object对象的toString方法的可以得到date对象,error对象,array对象不同的字符串,IE8一下不能区分dom,window和null对象。IE9+等现代浏览器连这些对象都可以区分。但是呢,他们返回的形式不是我们想要的[object Array]其中只有Array是我们想要的,而且对比typeof方法,首字母应该缩写,所以我们要对返回结果进行一些处理。
这里参照jquery的方法,进行一些简写
var typearr="Boolean Number String Function Array Date RegExp Object Error".split(" "); var typeobj={}; var tostring=typeobj.toString; for(var i=0;i<typearr.length;i++){ typeobj["[object "+typearr[i]+"]"]=typearr[i].toLowerCase(); } function type(obj){ return typeobj[tostring.apply(obj)]; }
运行结果如下:
IE8-中的null,undefined是object,因为IE8-的undefined也是object对象。到这里我们基本能得到我们想要的了,能区分date,array,error等类型。
最后我们看一下jquery的处理方法
function type( obj ) { if ( obj == null ) { return obj + ""; } return typeof obj === "object" || typeof obj === "function" ? class2type[ toString.call(obj) ] || "object" : typeof obj; }
通过加上这些判断运行结果:
加上了null的判断,我们还能区分出undefined和null对象,这样我们除了window和dom对象外,我们都能区分。而dom对象也不用这样区分,他有nodeType,nodeName等区分。而jquery代码中的return中的三元表达式是因为typeof比tostring方法运行快,可想而知,tostring方法毕竟还多了一个apply的处理过程。
最后我们把整个判断数据类型的方法整理成一个完整的方法。
(function(_){//使用闭包形式,避免全局变量的污染和变来那个冲突 var typearr="Boolean Number String Function Array Date RegExp Object Error".split(" "); var typeobj={}; var tostring=typeobj.toString; for(var i=0;i<typearr.length;i++){ typeobj["[object "+typearr[i]+"]"]=typearr[i].toLowerCase(); } function type(obj){ if ( obj == null ) { return obj + ""; } return typeof obj === "object" || typeof obj === "function" ? typeobj[ toString.call(obj) ] || "object" : typeof obj; } _.getType=type;//将类型判断方法添加到window全局对象上。 }(window)); var typename=getType(obj);//调用方式
很简短很简单的一个方法我们就能很轻松的判断数据的准确类型了,而且把这个弄明白的同时,你还顺便学习或者复习了call,apply,tostring等方法。