如何检测一个变量是否是一个数组

什么是确定JavaScript中的变量是否为数组的最佳事实上的标准跨浏览器方法?

搜索网络有许多不同的建议,一些很好,很多都是无效的。

例如,以下是一个基本的方法:

function isArray(obj) {
    return (obj && obj.length);
}

但是,请注意如果数组为空,或者obj实际上不是数组,但实现了长度属性等等会发生什么情况。

那么哪个实现在实际工作中是最好的,跨浏览器并且仍然有效地执行?


JS中对象的类型检查通过instanceof完成,即

obj instanceof Array

如果由于每个帧都有自己的Array对象而跨越帧边界传递对象,这将不起作用。 您可以通过检查对象的内部[[Class]]属性来解决此问题。 为了得到它,使用Object.prototype.toString() (这可以保证ECMA-262能够工作):

Object.prototype.toString.call(obj) === '[object Array]'

这两种方法只适用于实际数组,而不适用于arguments对象或节点列表等类似数组的对象。 由于所有类似数组的对象都必须具有数字length属性,因此我会检查它们是否如下所示:

typeof obj !== 'undefined' && obj !== null && typeof obj.length === 'number'

请注意,字符串将通过此检查,这可能会导致问题,因为IE不允许按索引访问字符串的字符。 因此,您可能希望将typeof obj !== 'undefined'更改为typeof obj === 'object'以排除不同于'object'类型的原语和主机对象。 这仍然会让字符串对象通过,这必须手动排除。

在大多数情况下,你真正想知道的是你是否可以通过数字索引遍历对象。 因此,检查对象是否具有名为0的属性可能是一个好主意,可以通过以下其中一种检查来完成:

typeof obj[0] !== 'undefined' // false negative for `obj[0] = undefined`
obj.hasOwnProperty('0') // exclude array-likes with inherited entries
'0' in Object(obj) // include array-likes with inherited entries

对象类型转换对于类似数组的基元(即字符串)正确工作是必需的。

以下是对JS数组进行健壮检查的代码:

function isArray(obj) {
    return Object.prototype.toString.call(obj) === '[object Array]';
}

和可迭代的(即非空的)类似数组的对象:

function isNonEmptyArrayLike(obj) {
    try { // don't bother with `typeof` - just access `length` and `catch`
        return obj.length > 0 && '0' in Object(obj);
    }
    catch(e) {
        return false;
    }
}

ECMAScript 5th Edition的到来为我们提供了测试变量是否为数组Array.isArray()的最可靠方法:

Array.isArray([]); // true

尽管这里接受的答案将适用于大多数浏览器的帧和窗口, 但它不适用于Internet Explorer 7及更低版本 ,因为从另一个窗口调用的数组的Object.prototype.toString将返回[object Object] ,而不是[object Array] 。 IE 9似乎也已经退化为这种行为(请参阅下面的更新修正)。

如果您对此感兴趣,可以阅读此博客文章,但我不会深入讨论解决方案的所有细节。 但是,如果您想要一种适用于所有浏览器的解决方案,则可以使用:

(function () {
    var toString = Object.prototype.toString,
        strArray = Array.toString(),
        jscript  = /*@cc_on @_jscript_version @*/ +0;

    // jscript will be 0 for browsers other than IE
    if (!jscript) {
        Array.isArray = Array.isArray || function (obj) {
            return toString.call(obj) == "[object Array]";
        }
    }
    else {
        Array.isArray = function (obj) {
            return "constructor" in obj && String(obj.constructor) == strArray;
        }
    }
})();

这不是完全牢不可破的,但它只会被有人试图打破它打破。 它解决了IE7和更低版本以及IE9中的问题。 该错误在IE 10 PP2中仍然存在,但它可能在发布之前得到修复。

PS,如果你不确定解决方案,那么我建议你测试它到你的心中的内容和/或阅读博客文章。 如果使用条件编译不舒服,还有其他可能的解决方案。


Crockford在“The Good Parts”的第106页有两个答案。 第一个检查构造函数,但会在不同的框架或窗口中给出错误的否定结果。 这是第二个:

if (my_value && typeof my_value === 'object' &&
        typeof my_value.length === 'number' &&
        !(my_value.propertyIsEnumerable('length')) {
    // my_value is truly an array!
}

Crockford指出,这个版本会将arguments数组标识为一个数组,即使它没有任何数组方法。

他对这个问题的有趣讨论从第105页开始。

这里还有一些有趣的讨论(后合格部分),其中包括这个建议:

var isArray = function (o) {
    return (o instanceof Array) ||
        (Object.prototype.toString.apply(o) === '[object Array]');
};

所有的讨论都让我从不想知道某个东西是不是数组。

链接地址: http://www.djcxy.com/p/19307.html

上一篇: How to detect if a variable is an array

下一篇: How to check if the target variable is in an array?