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系列检测函数简易实现完成。

相关