全部分类>> 编程

判断一个变量是否为数组

问题缘起

最近在看less.js的源码,想从中了解一些我还不知道的东西,看到了这样一段代码:

if (!Array.isArray) {
    Array.isArray = function(obj) {
        return Object.prototype.toString.call(obj) === "[object Array]" ||
               (obj instanceof Array);
    };
}

这段代码先判断Array是否有isArray属性,该属性在ES5中定义,如果判断的变量为数组返回true,否则返回false;在不支持ES5的浏览器中则定义了Array.isArray方法,用来判断变量是否为数组。

先撇开上面的代码,本文先来讨论,有哪些方法可以判断一个变量是否为数组?

typeof运算符

大家可能一开始就想到使用typeof运算符来获取变量的类型。但是typeof 运算符功能实在有效,只能返回如下字符串中的一种:”number”、”string”、”boolean”、”object”、”function”、”undefined”。

//尽管null不为对象,但是typeof返回为object
typeof null
typeof undefined
typeof []
typeof 2.322
typeof 'null'
typeof {}
typeof window.alert
typeof new Date();

instanceof

instanceof可以判断对象是否是由某个构造函数构造而来,在浏览器中测试[] instanceof Array,返回为true,看来这个方法可行,窃喜。

[] instanceof Array
[] instanceof Object
[] instanceof Date

constructor属性

每一个对象都有一个constructor对象,指向该对象的构造函数,所以可以写出如下的检测代码,首先通过typeof来检测变量是否为对象,然后进一步检测其构造函数是否为Array。

typeof arr == "object" && arr.constructor == Array

上述代码在检测跨框架(cross-frame)页面中的数组时,就会失败。原因是在不同框架(iframe)中创建的数组不会共享其prototype属性,见下面的例子。

//打开web.qq.com,该网站有很多iframe,可以运行下面的代码
var iframe_arr = new window.frames[0].Array;
iframe_arr instanceof Array // false
iframe_arr.constructor == Array // false

所以,使用constructor属性来判断有点不靠谱,不靠谱了就是不可行。

Object.prototype.toString检测

在本文开始,就提出了一种检测方法,该方法就是使用了Object.prototype.toString检测,可以解决上面的跨框架问题。

Object.prototype.toString(o)的执行过程如下: * 获取对象o的class属性 * 连接字符串:”[object “ + class属性 + “]” * 返回上述结果

var toString = Object.prototype.toString();
toString.call([]);
toString.call(new Date());
toString.call(/reg/ig);

扩展一下,扩展一下

下面的代码能够检测各种类型,例如isArray方法、isRegExp方法等等。

function __getClass(object) {
    return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1]; 
}

var is = {
    types: ["Array", "Boolean", "Date", "Number", "Object", "RegExp", "String", "Window", "HTMLDocument"];
}

for (var i = 0, c; c = is.types[i++];) {
    is[c] = (function(type){
        return function(obj) {
            return Object.prototype.toString.call(obj) === "[object " + type + "]";
        }
    })(c);
}

is.Array([])
is.Date(new Date())
is.RegExp(/reg/ig)

总结

Object.prototype.toString方法能够精确的检测对象类型,结合之前可行的instanceof方法,简直就是万全之策、无懈可击了。

前一篇:2012,在路上 后一篇:css preprocessors 返回首页