确定JavaScript中的变量是否为数组的最佳事实标准跨浏览器方法是什么?
在网上搜索有很多不同的建议,有些很好,很多都是无效的。
例如,以下是一种基本方法:
function isArray(obj) {
return (obj && obj.length);
}
但是,请注意如果数组为空,或者obj实际上不是数组但实现了长度属性等会发生什么。
那么哪种实现在实际工作方面是最好的,跨浏览器并且仍然有效地执行?
答案 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 === Array
或array 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)