我被告知不要使用。。。在JavaScript中使用数组。为什么不呢?
当前回答
因为。。。in通过持有数组的对象枚举,而不是数组本身。如果我向数组原型链中添加了一个函数,那么它也将包含在内。即。
Array.prototype.myOwnFunction = function() { alert(this); }
a = new Array();
a[0] = 'foo';
a[1] = 'bar';
for(x in a){
document.write(x + ' = ' + a[x]);
}
这将写入:
0 = foo 1 = bar myOwnFunction = function() { alert(this); }
而且,由于您永远无法确定不会向原型链中添加任何内容,因此只需使用for循环来枚举数组:
for(i=0,x=a.length;i<x;i++){
document.write(i + ' = ' + a[i]);
}
这将写入:
0 = foo 1 = bar
其他回答
孤立地说,在数组中使用for没有错。For-in迭代对象的属性名,在“现成”数组的情况下,财产对应于数组索引。(像length、toString等内置属性不包含在迭代中。)
然而,如果您的代码(或您正在使用的框架)将自定义财产添加到数组或数组原型中,那么这些财产将包含在迭代中,这可能不是您想要的。
一些JS框架,如Prototype修改了Array原型。像JQuery这样的其他框架则不然,因此使用JQuery,您可以在中安全地使用。
如果你有疑问,你可能不应该使用。
迭代数组的另一种方法是使用for循环:
for (var ix=0;ix<arr.length;ix++) alert(ix);
然而,这有一个不同的问题。问题是JavaScript数组可能有“洞”。如果您将arr定义为:
var arr = ["hello"];
arr[100] = "goodbye";
然后数组有两个项目,但长度为101。在中使用for将产生两个索引,而for循环将产生101个索引,其中99的值为undefined。
简短的回答:这不值得。
更长的答案:即使不需要顺序元素顺序和最佳性能,这也不值得。
长篇大论:这不值得。。。
使用for(数组中的var属性)将导致数组作为对象迭代,遍历对象原型链,最终执行速度比基于索引的for循环慢。for(…in…)不能保证按顺序返回对象财产,这可能是意料之中的。使用hasOwnProperty()和!用于筛选对象财产的isNaN()检查是一项额外的开销,导致它的执行速度更慢,并否定了首先使用它的主要原因,即因为它的格式更简洁。
出于这些原因,甚至不存在性能和便利性之间可接受的权衡。除非目的是将数组作为对象处理,并对数组的对象财产执行操作,否则实际上没有任何好处。
截至2016年(ES6),我们可能会使用for…for数组迭代,正如John Slegers已经注意到的那样。
我只想添加一个简单的演示代码,以使事情更清楚:
Array.prototype.foo = 1;
var arr = [];
arr[5] = "xyz";
console.log("for...of:");
var count = 0;
for (var item of arr) {
console.log(count + ":", item);
count++;
}
console.log("for...in:");
count = 0;
for (var item in arr) {
console.log(count + ":", item);
count++;
}
控制台显示:
for...of:
0: undefined
1: undefined
2: undefined
3: undefined
4: undefined
5: xyz
for...in:
0: 5
1: foo
换句话说:
对于的计数从0到5,并且还忽略Array.prototype.foo。它显示数组值。对于中只列出了5个,忽略了未定义的数组索引,但添加了foo。它显示数组属性名称。
因为。。。in通过持有数组的对象枚举,而不是数组本身。如果我向数组原型链中添加了一个函数,那么它也将包含在内。即。
Array.prototype.myOwnFunction = function() { alert(this); }
a = new Array();
a[0] = 'foo';
a[1] = 'bar';
for(x in a){
document.write(x + ' = ' + a[x]);
}
这将写入:
0 = foo 1 = bar myOwnFunction = function() { alert(this); }
而且,由于您永远无法确定不会向原型链中添加任何内容,因此只需使用for循环来枚举数组:
for(i=0,x=a.length;i<x;i++){
document.write(i + ' = ' + a[i]);
}
这将写入:
0 = foo 1 = bar
因为如果你不小心的话,它会迭代属于原型链上对象的财产。
您可以使用。。在中,只需确保使用hasOwnProperty检查每个属性。