有人告诉我不要在 JavaScript 的数组中使用 for...in。为啥?
原因在于一个结构:
var a = []; // Create a new empty array.
a[5] = 5; // Perfectly legal JavaScript that resizes the array.
for (var i = 0; i < a.length; i++) {
// Iterate over numeric indexes from 0 to 5, as everyone expects.
console.log(a[i]);}
/* Will display:
undefined
undefined
undefined
undefined
undefined
5
*/
有时候是完全不同的
var a = [];
a[5] = 5;for (var x in a) {
// Shows only the explicitly set index of "5", and ignores 0-4
console.log(x);}
/* Will display:
5
*/
还要考虑到 JavaScript 库可能会这样,这会影响你创建的数组:
// Somewhere deep in your JavaScript library...Array.prototype.foo = 1;
// Now you have no idea what the below code will do.var a = [1, 2, 3, 4, 5];for (var x in a){
// Now foo is a part of EVERY array and
// will show up here as a value of 'x'.
console.log(x);}
/* Will display:
0
1
2
3
4
foo
*/
for-in语句本身没错,但是它可能会用错,例如,在数组或类似数组的对象上进行迭代。
For-in 语句的用途是枚举多个对象属性。该语句将在原型链中上行,同时枚举了多个继承的属性,但有时不需要的。
此外,迭代的顺序不受 spec. 的保证,这意味着如果您想“迭代”一个数组对象,使用这个语句,您不能确保属性(数组索引)将以数字顺序访问。
例如,在 JScript (IE 8)中,甚至在 Array 对象上的枚举次序被定义为:
var array = [];
array[2] = 'c';
array[1] = 'b';
array[0] = 'a';
for (var p in array) {
//... p will be "2", "1" and "0" on IE}
另外,说到继承的属性,例如,扩展 Array.prototype 对象(像 MooTools 这样的一些库一样) ,这些属性也会被枚举:
Array.prototype.last = function () { return this[this.length-1]; };
for (var p in []) { // an empty array
// last will be enumerated}
正如我前面所说的,对数组或类似数组的对象进行迭代时,最好使用顺序循环,比如普通的 for/while 循环。
当你只想枚举一个对象自己的属性(那些没有被继承的) ,你可以使用 hasOwnProperty方法:
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
// prop is not inherited
}}
有些人甚至建议直接从 Object.prototype 调用该方法,以避免在有人向我们的对象添加名为 hasOwnProperty 的属性时出现问题:
for (var prop in obj) {
if (Object.prototype.hasOwnProperty.call(obj, prop)) {
// prop is not inherited
}}
因为 for... 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