JS检测数据类型
在Javascript应用场景中经常需要检测数据的类型。比如写一个简单的计算功能,你可能检测输入的参数是否是Number类型;在使用回调函数的时候,你可能要验证代表回调函数的那个值是不是function;再比如你想对某个对象执行深拷贝的时候,你可能需要判断拷贝对象的某些属性是不是Array类型。
一些优秀的类库框架都会实现一些检测数据的函数,比如JQuery有isFunction、isArray等等,ExtJs也有类似的函数。
今天来简单实现11个检测数据类型的函数。
1.简述typeof操作符
我们常常用typeof操作符来检测String、Undefined、Number、Boolean四种类型,因为用它检测这四种类型的结果是1对1的;其它结果如object、function对应的类型不唯一。
//检测String、Number、Undefined、Boolean类型结果是可靠的 console.log("undefined", typeof undefined);//undefined console.log("boolean", typeof false);//boolean console.log("number", typeof 1);//number console.log("string", typeof string);//string
typeof 检测Null类型结果是object,检测对象字面量也会得到object结果。当使用它检测出object时,我们还需额外的检测逻辑才能具体确定数据类型。
//我们还需要额外的逻辑才能进一步甄别null与对象字面量 console.log("null", typeof null);//object
console.log("{}", typeof {});//object
console.log("正则", typeof (/[a]/g));//IE与Firefox返回Object、部分浏览器返回function
typeof检测function类型时会得到function结果,但是Safari 5及之前的版本和Chrome 7及之前的版本中使用typeof检测正则表达式也会返回function结果。
Ecma262规定任何内部实现[[Call]]函数的对象都应该在typeof操作中返回function,上述浏览器中正则表达式实现了该函数,所以导致返回function结果也会有不确定。
2.简述instanceof操作符
instanceof操作符我们通常用来检测构造器以之确定自定义引用类型。所以在一些框架类库中,检测自定义数据类型可以用它来实现内部逻辑。
function A() {} function B() {} function C() {} C.prototype = new A(); var c = new C(); console.log("{} instanceof Object", {} instanceof Object); console.log("c instanceof A", c instanceof A); console.log("c instanceof B", c instanceof B); console.log("c instanceof Object", c instanceof Object); function isA(a) { return a instanceof A; } var b = new B(); console.log(isA(c));//true console.log(isA(b));//false
上面代码里我自定义了A、B、C三种类型,并且C使用原型链继承形式继承了A。所以在isA函数中检测c的实例得到true,而B的实例与A没继承关系,所以返回false。
有一点值得注意的是instanceof也并不是绝对可靠。跨域通信场景中(frame框架),两个来自不同域相同实现的类型是无法检测出true的。
3.简述Object.prototype.toString
Object.prototype.toString常用来判断对象值属于哪种内置属性,它返回一个JSON字符串——"[object 数据类型]"。
由于许多引用类型都重写了Object继承来的的toStrong方法,所以我们通常使用call或者apply借用Object.prototype.toString函数来判断数据类型。
当然,这样调用的默认前提是Object.prototype.toString没有被重写。
//定义toString变量是为了简便书写,同时降低作用域链检索的性能损耗 var toString = Object.prototype.toString; console.log(toString.call(1));//[object Number] console.log(toString.call(undefined));//[object Undefined] console.log(toString.call(null));//[object Null] console.log(toString.call(false));//[object Boolean] console.log(toString.call("s"));//[object String] console.log(toString.call({}));//[object Object] console.log(toString.call(/[a]/g));//[object RegExp] console.log(toString.call(function(){}));//[object Function]
4.is系列函数的简易实现
在明白数据类型怎么检测后,下面我们来简单实现is系列检测函数。
var dataType = { '[object Null]' : 'null', '[object Undefined]' : 'undefiend', '[object Boolean]' : 'boolean', '[object Number]' : 'number', '[object String]' : 'string', '[object Function]' : 'function', '[object Array]' : 'array', '[object Date]' : 'date', '[object RegExp]' : 'regexp', '[object Object]' : 'object', '[object Error]' : 'error' }, toString = Object.prototype.toString; function type(obj) { return dataType[toString.call(obj)]; } //生成is系列函数 function createValidType() { for(var p in dataType) { var objType = p.slice(8, -1); (function(objType) { window['is' + objType] = function(obj) { return type(obj) === objType.toLowerCase(); } })(objType) } } createValidType(); console.log(isObject({}));//true console.log(isDate(new Date()));//true console.log(isBoolean(false));//true console.log(isString(1));//false console.log(isError(1));//false console.log(isError(new Error()));//true console.log(isArray([]));//true console.log(isArray(1));//false
上面代码里分别实现了isNull、isUndefined、isBoolean、isNumber、isString、isFunction、isArray、isDate、isRegExp、isObject、isError这11个检测函数。同时也实现了type函数,用以检测数据类型。
console.log(type({}));//"object" console.log(type(new Date()));//"date" console.log(type(false));//"boolean" console.log(type(1));//"number" console.log(type(1));//"number" console.log(type(new Error()));//"error" console.log(type([]));//"array" console.log(type(1));//"number"
createValidType函数巧用闭包保存数据状态的特性,批量生成is系列函数。
至此,is系列检测函数简易实现完成。