确定JavaScript中的变量是否为数组的最佳事实标准跨浏览器方法是什么?
在网络上搜索时,有很多不同的建议,有些是好的,有些是无效的。
例如,以下是一种基本方法:
function isArray(obj) {
return (obj && obj.length);
}
但是,请注意,如果数组为空,或者obj实际上不是数组而是实现了length属性等,会发生什么情况。
那么,从实际工作,跨浏览器和仍有效执行的角度来看,哪种实现是最佳的呢?
确定JavaScript中的变量是否为数组的最佳事实标准跨浏览器方法是什么?
在网络上搜索时,有很多不同的建议,有些是好的,有些是无效的。
例如,以下是一种基本方法:
function isArray(obj) {
return (obj && obj.length);
}
但是,请注意,如果数组为空,或者obj实际上不是数组而是实现了length属性等,会发生什么情况。
那么,从实际工作,跨浏览器和仍有效执行的角度来看,哪种实现是最佳的呢?
Answers:
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;
}
}
hasOwnProperty
方法,因此只需在您的前面instanceof
加上obj.hasOwnProperty &&
;即可。另外,这仍然是IE7的问题吗?我通过任务管理器进行的简单测试表明,在最小化浏览器之后,内存已被回收...
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,如果您不确定解决方案,那么我建议您对它的内容进行测试和/或阅读博客文章。如果您不满意使用条件编译,那么这里还有其他潜在的解决方案。
isArray
是否不会以其他文档模式下创建的数组返回true?我得看看这个,当我得到一些时间,但我觉得做的最好的事情是文件上连接一个bug,因此它可以固定在IE 10
克罗克福德在“好零件”的第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]');
};
所有的讨论都使我永远不想知道某个东西是否是数组。
jQuery实现了isArray函数,这建议最好的方法是
function isArray( obj ) {
return toString.call(obj) === "[object Array]";
}
(摘自jQuery v1.3.2的代码段-略有调整,以脱离上下文)
Object.prototype.toString()
-这是不太可能打破
窃取大师John Resig和jquery:
function isArray(array) {
if ( toString.call(array) === "[object Array]") {
return true;
} else if ( typeof array.length === "number" ) {
return true;
}
return false;
}
typeof
是标准化的吗?
一旦确定它是一个数组,您将如何处理该值?
例如,如果您打算枚举包含的值(如果它看起来像一个数组)或者它是一个用作哈希表的对象,那么下面的代码将获得所需的代码(当闭包函数返回任何其他值时,此代码停止请注意,它不会遍历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] );
}
})
}
for..in
很不好[tm])
for..in
遍历对象的可枚举属性;您不应该将其与数组一起使用,因为:(1)它很慢;(2)不保证保留订单;(3)由于ES3不包含任何设置DontEnum属性的方法,因此它将包含对象中任何用户定义的属性集或其任何原型;可能还有其他一些问题让我忘了
如果您在CouchDB(SpiderMonkey)中执行此操作,请使用
Array.isArray(array)
作为array.constructor === Array
或array instanceof Array
不工作。使用array.toString() === "[object Array]"
确实可以工作,但相比起来显得有些狡猾。
如果要跨浏览器,则需要jQuery.isArray。
在w3school上,有一个例子应该很标准。
要检查变量是否为数组,他们使用类似于此的内容
function arrayCheck(obj) {
return obj && (obj.constructor==Array);
}
在Chrome,Firefox,Safari和ie7上进行了测试
constructor
进行类型检查是IMO太脆; 使用建议的替代方法之一,而不是
constructor
是原型对象的常规DontEnum属性;只要没有人做任何愚蠢的事情,对于内置类型来说这可能不是问题,但是对于用户定义的类型,这很容易做到;我的建议:始终使用instanceof
,它检查原型链,并且不依赖于可以任意覆盖的属性
替换Array.isArray(obj)
为obj.constructor==Array
样品:
Array('44','55').constructor==Array
返回true(IE8 / Chrome)
'55'.constructor==Array
返回假(IE8 / Chrome)