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


当前回答

我认为我没有什么要补充的,比如Triptych的答案或CMS关于为什么使用for。。。在某些情况下应避免。

然而,我想补充一点,在现代浏览器中,有一种替代。。。在这种情况下。。。无法使用中的。另一种选择是。。。第页,共页:

for (var item of items) {
    console.log(item);
}

注:

遗憾的是,没有版本的Internet Explorer支持。。。(Edge 12+确实如此),因此您必须等待一段时间,直到可以在客户端生产代码中使用它。然而,在服务器端JS代码中使用它应该是安全的(如果您使用Node.JS)。

其他回答

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
  }
}

您应该只在属性列表上使用for(var x in y),而不是在对象上(如上所述)。

主要有两个原因:

One

就像其他人所说的那样,您可能会得到不在数组中或从原型继承的密钥。因此,假设库向Array或Object原型添加了一个属性:

Array.prototype.someProperty = true

您可以将其作为每个阵列的一部分:

for(var item in [1,2,3]){
  console.log(item) // will log 1,2,3 but also "someProperty"
}

可以使用hasOwnProperty方法解决此问题:

var ary = [1,2,3];
for(var item in ary){
   if(ary.hasOwnProperty(item)){
      console.log(item) // will log only 1,2,3
   }
}

但这对于使用for in循环迭代任何对象都是正确的。

Two

通常,数组中项目的顺序很重要,但for in循环不一定以正确的顺序迭代,这是因为它将数组视为对象,这是在JS中实现的方式,而不是数组。这看起来是一件小事,但它确实会破坏应用程序,而且很难调试。

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

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

一个重要的方面是。。。in-only迭代包含在对象中的财产,该对象的可枚举属性属性设置为true。因此,如果尝试使用for对对象进行迭代。。。然后,如果任意财产的可枚举属性为false,则可能会丢失这些属性。很有可能更改普通Array对象的可枚举属性属性,以便不枚举某些元素。虽然一般来说,属性属性倾向于应用于对象中的函数财产。

可以通过以下方式检查财产的可枚举属性属性的值:

myobject.propertyIsEnumerable('myproperty')

或获取所有四个属性属性:

Object.getOwnPropertyDescriptor(myobject,'myproperty')

这是ECMAScript 5中提供的一个特性——在早期版本中,无法更改可枚举属性属性的值(它总是设置为true)。