如何检测变量是否为数组

时间:2009-06-29 13:48:22

标签: javascript arrays

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

在网上搜索有很多不同的建议,有些很好,很多都是无效的。

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

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

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

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

12 个答案:

答案 0 :(得分:156)

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;
    }
}

答案 1 :(得分:38)

ECMAScript第5版的到来为我们提供了最可靠的测试变量是否为数组的方法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中的问题。 The bug still exists in IE 10 PP2,但可能会在发布之前修复。

PS,如果您对解决方案不确定,那么我建议您根据自己的内容进行测试和/或阅读博客文章。如果您对使用条件编译感到不舒服,还有其他可能的解决方案。

答案 2 :(得分:8)

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页开始。

还有一个有趣的讨论(后好的部分)here,其中包括这个提议:

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

所有的讨论都让我永远不想知道某些东西是否是数组。

答案 3 :(得分:2)

jQuery实现了一个isArray函数,它建议最好的方法是

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

(取自jQuery v1.3.2的片段 - 略微调整以脱离上下文)

答案 4 :(得分:2)

从大师John Resig和jquery偷窃:

function isArray(array) {
    if ( toString.call(array) === "[object Array]") {
        return true;
    } else if ( typeof array.length === "number" ) {
        return true;
    }
    return false;
}

答案 5 :(得分:1)

一旦你确定它是一个数组,你打算怎么做?

例如,如果您打算枚举包含的值,如果看起来像一样,或者如果它是一个用作哈希表的对象,那么下面的代码就会得到你想要的(当闭包函数返回“undefined”以外的任何内容时,此代码会停止。请注意,它不会迭代COM容器或枚举;这只是读者的练习:

function iteratei( o, closure )
{
    if( o != null && o.hasOwnProperty )
    {
        for( var ix in seq )
        {
            var ret = closure.call( this, ix, o[ix] );
            if( undefined !== ret )
                return ret;
        }
    }
    return undefined;
}

(注意:“o!= null”测试null& undefined)

使用示例:

// Find first element who's value equals "what" in an array
var b = iteratei( ["who", "what", "when" "where"],
    function( ix, v )
    {
        return v == "what" ? true : undefined;
    });

// Iterate over only this objects' properties, not the prototypes'
function iterateiOwnProperties( o, closure )
{
    return iteratei( o, function(ix,v)
    {
        if( o.hasOwnProperty(ix) )
        {
            return closure.call( this, ix, o[ix] );
        }
    })
}

答案 6 :(得分:1)

如果你在CouchDB(SpiderMonkey)中这样做,那么使用

Array.isArray(array)

array.constructor === Arrayarray instanceof Array不起作用。使用array.toString() === "[object Array]"确实有用,但相比之下看起来很狡猾。

答案 7 :(得分:0)

如果您想要跨浏览器,则需要jQuery.isArray

答案 8 :(得分:0)

w3school上有一个非常标准的例子。

要检查变量是否为数组,他们会使用与此类似的内容

function arrayCheck(obj) { 
    return obj && (obj.constructor==Array);
}

在Chrome,Firefox,Safari,ie7

上测试

答案 9 :(得分:-2)

可以在PHPJS site上找到此功能的最佳研究和讨论版本之一。您可以链接到包裹,也可以转到function directly。我强烈建议该网站在JavaScript中构建相当好的PHP函数。

答案 10 :(得分:-2)

没有足够的引用等​​于构造函数。有时他们有不同的构造函数引用。所以我使用它们的字符串表示。

function isArray(o) {
    return o.constructor.toString() === [].constructor.toString();
}

答案 11 :(得分:-4)

Array.isArray(obj)替换为obj.constructor==Array

样品:

Array('44','55').constructor==Array返回true(IE8 / Chrome)

'55'.constructor==Array返回false(IE8 / Chrome)