如何在JavaScript中检查变量是否为数组?

2104

如何在JavaScript中检查一个变量是否为数组?

if (variable.constructor == Array)

3
检查一个对象是否是数组有一些特定的注意事项... Peter的答案是你应该使用的唯一答案。 - aleemb
1
@Andy 看起来我的答案不是最好的。也许你应该选择一个不同的答案作为被接受的答案? - Peter Smit
2
很好的观点,彼得。我没有意识到你的答案会收到这样的评论。我想我早已开始使用JQuery.isArray函数来检查数组,有趣的是,它与这里给出的任何其他答案实现方式都不同。我已将受欢迎的答案标记为正确。 - Andy McCluggage
1
抱歉,那是错误的。我深入了解了一下(截至1.6.2版本),JQuery仍然使用形式为...toString.call(obj) === "[object Array]"的比较进行类型检查。 - Andy McCluggage
8
这个问题以前曾经被问过。...不,那个问题是在这个问题之后被问的。 - Dexygen
显示剩余3条评论
26个回答

1983

有几种方法可以检查一个变量是否为数组。最好的解决方案是您选择的那个。

variable.constructor === Array

这是Chrome最快的方法,很可能在其他浏览器中也是如此。所有数组都是对象,因此检查构造函数属性对于JavaScript引擎来说是一种快速的过程。

如果您在查找对象属性是否为数组方面遇到问题,则必须首先检查该属性是否存在。

variable.prop && variable.prop.constructor === Array

其他一些方法包括:

Array.isArray(variable)

2019年5月23日更新,使用Chrome 75,感谢@AnduAndrici提出的问题让我重新审视这个问题。 在我看来,最后一个例子是最丑陋的,但也是最快的。虽然速度比第一个例子慢了大约2-5%,但很难分辨。非常实用!结果令人印象深刻。Array.prototype实际上是一个数组,您可以在此处https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray上阅读更多信息。

variable instanceof Array

这种方法的运行速度大约是第一个示例的 1/3。仍然相当可靠,看起来更清晰,如果您关注优美的代码而不是性能。注意,检查数字不起作用,因为 variable instanceof Number 总是返回 false更新:现在 instanceof 的速度提高了 2/3!

所以又有了更新。

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

这个方法检测数组的速度最慢,但是它可以处理你需要的任何类型。不过,既然你要查找的是数组,那么就使用上面最快的方法吧。

另外,我进行了一些测试:http://jsperf.com/instanceof-array-vs-array-isarray/35,所以来试试吧。

注意:由于 jsperf.com 当前无法访问,@EscapeNetscape 创建了另一个测试 http://jsben.ch/#/QgYAV。我希望原始链接能在 jsperf 恢复时保留下来。


11
请注意,如果您不确定变量是否已定义或者可能为 null,请先进行这些检查,因为这些通常是没有构造函数的常见值/对象。 - Michael Scott Asato Cuthbert
7
请注意:如果变量为空,则“variable.constructor === Array”将抛出异常,但“variable instanceof Array”不会! - GorvGoyl
6
从Chrome 59开始,isArray()的速度显著提高,因此我认为在所有情况下都应该使用isArray(),没有任何不使用它的理由。 - Hedley Smith
11
很多修改使得你的回答难以阅读。这就是我要给你点“踩”的原因... - Clint Eastwood
5
如果你要编辑你的回答,请考虑让那些之前没有阅读过它的人更容易阅读。 - AtilioA
显示剩余25条评论

1167

你也可以使用:

if (value instanceof Array) {
  alert('value is Array!');
} else {
  alert('Not an array');
}

这对我来说是一个相当优雅的解决方案,但各有所好。

编辑:

从ES5开始,现在也有:

Array.isArray(value);

但是在老的浏览器上,这将会出现问题,除非你使用了polyfill(基本上是...IE8或类似的浏览器)。


27
如果你不涉及多个框架,我建议并且坚持使用 "instanceof" 运算符来检查对象类型。这是正确的检查方式。 - BYK
45
唯一可能失败的情况是当您试图测试某个变量是否为数组或对象时,因为 Array instanceof Object == true - Pierre
1
为了强调@BYK的观点,这仅适用于同一帧中的对象。如果您正在使用多个帧,请不要依赖此功能! - Cory Klein
5
如果您仍然活跃,请更新您的答案以反映自ES5以来我们拥有Array.isArray。 - Nobbynob Littlun
5
请参考Fela Winkelmolen的回答,其中提到了Array.isArray方法。至于这个回答,通过编辑将一个回答改变成另一个回答可能不是一个好主意。 - muffin
显示剩余8条评论

86

在现代浏览器(和一些传统浏览器)中,您可以执行以下操作:

Array.isArray(obj)

(浏览器支持情况:Chrome 5、Firefox 4.0、IE 9、Opera 10.5 和 Safari 5)

如果你需要支持旧版本的 IE,你可以使用es5-shim 来填充 Array.isArray;或者添加以下内容:

# only implement if no native implementation is available
if (typeof Array.isArray === 'undefined') {
  Array.isArray = function(obj) {
    return Object.prototype.toString.call(obj) === '[object Array]';
  }
};
如果您使用jQuery,可以使用jQuery.isArray(obj)$.isArray(obj)。如果您使用underscore,则可以使用_.isArray(obj)。如果您不需要检测在不同框架中创建的数组,也可以使用instanceof
obj instanceof Array
注意:可以用于访问函数参数的 arguments 关键字并非数组,尽管它(通常)表现得像一个数组:

var func = function() {
  console.log(arguments)        // [1, 2, 3]
  console.log(arguments.length) // 3
  console.log(Array.isArray(arguments)) // false !!!
  console.log(arguments.slice)  // undefined (Array.prototype methods not available)
  console.log([3,4,5].slice)    // function slice() { [native code] } 
}
func(1, 2, 3)


3
这可能是目前最好、最现代的方法。我在MDN上看到它和填充程序一起使用,这意味着Mozilla信任它。https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray - John
你不是漏了 prototype 吗?看起来应该是 Object.prototype.toString.call - Brock
我们还可以确定对象是否具有数组中存在的方法,例如push、splice等。 - aj go

82

有多种解决方案,每个方案都有其特殊之处。这个页面提供了一个很好的概述。其中一种可能的解决方案是:

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

如果你仔细阅读,它说当你处理多帧文档时需要使用此方法,但这并不推荐。这种方法很容易在“toString”函数的微小更改上出现问题。 - BYK
4
因此,提供了链接以便Brett可以查看它们,并确定他的功能需要在哪种情况下起作用。 - Peter Smit
1
请看我的回答。我推荐Peter Smit的方法。 - Brian
6
这种方法是由Mozilla推荐的 - Hank

76
我注意到有人提到了jQuery,但我不知道有一个 isArray() 函数。结果发现它是在1.3版本中添加的。
jQuery按照Peter的建议实现了它:
isArray: function( obj ) {
    return toString.call(obj) === "[object Array]";
},

已经对jQuery充满信心(特别是它们用于跨浏览器兼容性的技术),如果升级不会导致太多问题,我将升级到1.3版本并使用他们的函数,或者直接在我的代码中使用此建议方法。

非常感谢您的建议。


参见这篇文章,对该主题进行了很好的讨论。结论是使用这个解决方案。 - Nick G.
1
这让我在IE10中出现了SCRIPT65535错误。 - polm23

55

这是一个老问题,但我找到了一个非常优美的解决方案,想要分享。

在数组中添加一个原型会使它变得非常简单。

Array.prototype.isArray = true;

如果你想测试一个对象是否为数组,现在只需检查新属性即可。

var box = doSomething();

if (box.isArray) {
    // do something
}

如果它是一个数组,那么isArray才可用。


5
原文:@Vitimtk 原型充当实际对象的备选项,因此即使涉及的数组已存在,这也应该起作用。 当然,在处理源代码行之前,它是无法起作用的。翻译:原型是实际对象的备选方案,因此即使涉及的数组已经存在,这个方法也可以使用。当然,在处理源代码行之前,它是无法生效的。 - Markus Bruckner
38
假设没有人执行Object.prototype.isArray = true;!:( - ErikE
14
请注意,在 ES5 中,Array.isArray 是一个方法(例如 Array.isArray([1,2,3]) === true),所以 @ErikE 并不是在恶意挑衅。我建议避免使用这个回答,因为它会在某些现代浏览器中破坏代码。 - JaredMcAteer
4
我的“方案”可以让您使用{}.isArray === true,这正是我的初衷... - ErikE
2
在我看来,修改数据类型的原型是一种不好的做法。 - BentOnCoding
显示剩余3条评论

48

根据 Crockford 的说法:

function typeOf(value) {
    var s = typeof value;
    if (s === 'object') {
        if (value) {
            if (value instanceof Array) {
                s = 'array';
            }
        } else {
            s = 'null';
        }
    }
    return s;
}
Crockford提到的主要问题是无法正确确定在不同上下文中创建的数组,例如window。 如果这不足以解决问题,该页面还有一个更复杂的版本。

35
如果你只需要处理 EcmaScript 5 及以上版本的话,你可以使用内置的 Array.isArray 函数。
例如:
Array.isArray([])    // true
Array.isArray("foo") // false
Array.isArray({})    // false

30

我个人喜欢Peter的建议:https://dev59.com/K3RA5IYBdhLWcg3w9izq#767499(适用于ECMAScript 3。对于ECMAScript 5,请使用Array.isArray()

然而,帖子上的评论表明,如果toString()被更改了,那种检查数组的方式将会失败。如果你想要更加具体并确保toString()没有被更改,并且对象的类属性没有问题([object Array]是一个数组对象的类属性),那么我建议像这样做:

//see if toString returns proper class attributes of objects that are arrays
//returns -1 if it fails test
//returns true if it passes test and it's an array
//returns false if it passes test and it's not an array
function is_array(o)
{
    // make sure an array has a class attribute of [object Array]
    var check_class = Object.prototype.toString.call([]);
    if(check_class === '[object Array]')
    {
        // test passed, now check
        return Object.prototype.toString.call(o) === '[object Array]';
    }
    else
    {
        // may want to change return value to something more desirable
        return -1; 
    }
}
请注意,在JavaScript权威指南第6版的7.10章节中,它说Array.isArray()在ECMAScript 5中是使用Object.prototype.toString.call()实现的。还要注意,如果你担心toString()的实现发生变化,你也应该担心其他所有内置方法的变化。为什么要使用push()?有人可能会对其进行更改!这种方法很愚蠢。上述检查是提供给那些担心toString()变化的解决方案,但我认为这个检查是不必要的。

1
对 ECMAScript 5 标准的选择很明智。虽然不能保证浏览器支持它,但这应该是检查新代码的第一种方式。 - styfle
我先说一下,这有点超出我的能力范围。不过,像这样的测试会更加健壮吗?:return Object.prototype.toString.call(o) === Object.prototype.toString.call([]); - Grant Lindsay

20

当我发布这个问题时,我使用的JQuery版本不包括isArray函数。如果有的话,我可能会直接使用它,并相信这种实现方法是执行特定类型检查的最佳浏览器无关方式。

既然JQuery现在提供了这个函数,我会始终使用它...

$.isArray(obj);

(截至版本1.6.2)此仍然是使用字符串比较实现的形式

toString.call(obj) === "[object Array]"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接