我被告知不要使用。。。在JavaScript中使用数组。为什么不呢?


当前回答

除了其他答案中给出的原因外,如果需要计算计数器变量,您可能不想使用“for…In”结构,因为循环会迭代对象财产的名称,因此该变量是一个字符串。

例如

for (var i=0; i<a.length; i++) {
    document.write(i + ', ' + typeof i + ', ' + i+1);
}

将写入

0, number, 1
1, number, 2
...

鉴于

for (var ii in a) {
    document.write(i + ', ' + typeof i + ', ' + i+1);
}

将写入

0, string, 01
1, string, 11
...

当然,这可以通过包括

ii = parseInt(ii);

但第一种结构更直接。

其他回答

for in语句本身并不是一个“坏习惯”,但是它可能被错误地使用,例如,用于迭代数组或类似数组的对象。

for-in语句的目的是枚举对象财产。该语句将出现在原型链中,也会枚举继承的财产,这有时是不需要的。

此外,规范并不能保证迭代的顺序,这意味着如果要“迭代”数组对象,那么使用此语句无法确保财产(数组索引)将按数字顺序访问。

例如,在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
  }
}

A代表。。。in循环总是枚举键。对象财产键始终是String,甚至是数组的索引财产:

var myArray = ['a', 'b', 'c', 'd'];
var total = 0
for (elem in myArray) {
  total += elem
}
console.log(total); // 00123

此外,由于语义的原因,在treats数组(即与任何其他JavaScript对象相同)中使用的方法与其他流行语言不一致。

// C#
char[] a = new char[] {'A', 'B', 'C'};
foreach (char x in a) System.Console.Write(x); //Output: "ABC"

// Java
char[] a = {'A', 'B', 'C'};
for (char x : a) System.out.print(x);          //Output: "ABC"

// PHP
$a = array('A', 'B', 'C');
foreach ($a as $x) echo $x;                    //Output: "ABC"

// JavaScript
var a = ['A', 'B', 'C'];
for (var x in a) document.write(x);            //Output: "012"

截至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。它显示数组属性名称。

除了其他问题之外,“for…In”语法可能更慢,因为索引是字符串,而不是整数。

var a = ["a"]
for (var i in a)
    alert(typeof i)  // 'string'
for (var i = 0; i < a.length; i++)
    alert(typeof i)  // 'number'