如何检测一个变量是否是一个数组
什么是确定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