JavaScript for … in vs for

JavaScript for…in vs for

你认为…在循环和循环之间有很大的区别吗?你喜欢用什么类型的"for",为什么?

假设我们有一组关联数组:

1
var myArray = [{'key': 'value'}, {'key': 'value1'}];

所以我们可以迭代:

1
for (var i = 0; i < myArray.length; i++)

还有:

1
for (var i in myArray)

我看不出有什么区别。是否存在性能问题?


选择应该基于哪种成语是最好理解的。

数组的迭代使用:

1
2
for (var i = 0; i < a.length; i++)
   //do stuff with a[i]

用作关联数组的对象使用以下方法迭代:

1
2
for (var key in o)
  //do stuff with o[key]

除非你有惊天动地的理由,否则坚持既定的使用模式。


DouglasCrockford在javascript中建议:好的部分(第24页),以避免使用for in语句。

如果使用for in循环对象中的属性名,则不会对结果进行排序。更糟的是:您可能会得到意外的结果;它包括从原型链继承的成员和方法的名称。

除了属性之外的所有内容都可以用.hasOwnProperty过滤掉。此代码示例执行您最初可能需要的操作:

1
2
3
4
5
for (var name in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, name)) {
        // DO STUFF
    }
}


仅供参考-jquery用户

jquery的each(callback)方法默认使用for( ; ; )循环,只有长度为undefined时才会使用for( in )

因此,在使用这个函数时,可以安全地假定正确的顺序。

例子:

1
2
3
4
$(['a','b','c']).each(function() {
    alert(this);
});
//Outputs"a" then"b" then"c"

使用这种方法的缺点是,如果您正在执行一些非UI逻辑,那么您的函数就不太容易移植到其他框架。each()函数最好保留用于jquery选择器,否则for( ; ; )可能是明智的。


根据您使用的循环类型和浏览器的不同,会存在性能差异。

例如:

1
for (var i = myArray.length-1; i >= 0; i--)

在某些浏览器上的速度几乎是以下速度的两倍:

1
for (var i = 0; i < myArray.length; i++)

但是,除非您的数组很大,或者您经常循环它们,否则所有这些都足够快。我严重怀疑数组循环在您的项目(或任何其他项目)中是一个瓶颈。


请注意,现在广泛支持本机array.foreach方法。


更新了2012年所有主要浏览器的当前版本的答案-Chrome、Firefox、IE9、Safari和Opera支持ES5的本机array.foreach。

除非您有理由以本机方式支持IE8(请记住,可以向这些用户提供ES5 Shim或Chrome框架,这将提供适当的JS环境),否则简单地使用该语言的适当语法会更干净:

1
2
3
myArray.forEach(function(item, index) {
    console.log(item, index);
});

array.foreach()的完整文档位于MDN。


我认为你应该根据自己的需要选择迭代法。我建议您实际上不要使用for in结构遍历本机Array。正如蔡斯?塞伯特(ChaseSeibert)刚才指出的那样,它的速度要慢得多,而且与原型框架不兼容。

对于不同的循环样式,有一个很好的基准,如果您使用JavaScript的话,您绝对应该看看。不要过早地进行优化,但是你应该把那些东西放在脑后的某个地方。

我将使用for in获取对象的所有属性,这在调试脚本时特别有用。例如,当我探索不熟悉的对象时,我喜欢把这句话放在手边:

1
2
l = ''; for (m in obj) { l += m + ' => ' + obj[m] + '
'
} console.log(l);

它将整个对象的内容(连同方法体)转储到我的Firebug日志中。非常方便。


使用foreach跳过原型链

上面@nailer答案的一个快速补充,使用foreach with object.keys意味着您可以避免在原型链上迭代,而不必使用hasownproperty。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var Base = function () {
    this.coming ="hey";
};

var Sub = function () {
    this.leaving ="bye";
};

Sub.prototype = new Base();
var tst = new Sub();

for (var i in tst) {
    console.log(tst.hasOwnProperty(i) + i + tst[i]);
}

Object.keys(tst).forEach(function (val) {
    console.log(val + tst[val]);
});


当数组是稀疏的时,这两个不相同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var array = [0, 1, 2, , , 5];

for (var k in array) {
  // Not guaranteed by the language spec to iterate in order.
  alert(k);  // Outputs 0, 1, 2, 5.
  // Behavior when loop body adds to the array is unclear.
}

for (var i = 0; i < array.length; ++i) {
  // Iterates in order.
  // i is a number, not a string.
  alert(i);  // Outputs 0, 1, 2, 3, 4, 5
  // Behavior when loop body modifies array is clearer.
}


这是我做的事。

1
2
3
4
5
function foreach(o, f) {
 for(var i = 0; i < o.length; i++) { // simple for loop
  f(o[i], i); // execute a function and make the obj, objIndex available
 }
}

这就是您将如何使用它
这将用于数组和对象(如HTML元素列表)

1
2
3
4
5
6
7
8
9
10
foreach(o, function(obj, i) { // for each obj in o
  alert(obj); // obj
  alert(i); // obj index
  /*
    say if you were dealing with an html element may be you have a collection of divs
  */

  if(typeof obj == 'object') {
   obj.style.marginLeft = '20px';
  }
});

我刚做了这个,所以我愿意接受建议:)


我会根据我想要引用项目的方式使用不同的方法。

如果只需要当前项,请使用foreach。

如果需要索引器进行相对比较,请使用。(即,这与上一项/下一项相比如何?)

我从未注意到性能差异。在担心性能问题之前,我会一直等到出现性能问题。


当心!

例如,如果您有几个脚本标记,并且正在标记属性中搜索信息,则必须在for循环中使用.length属性,因为它不是简单数组,而是一个htmlcollection对象。

https://developer.mozilla.org/en/dom/htmlcollection网站

如果您使用foreach语句for(您列表中的var i),它将在大多数浏览器中返回htmlcollection的蛋白质和方法!

1
2
3
4
5
6
7
var scriptTags = document.getElementsByTagName("script");

for(var i = 0; i < scriptTags.length; i++)
alert(i); // Will print all your elements index (you can get src attribute value using scriptTags[i].attributes[0].value)

for(var i in scriptTags)
alert(i); // Will print"length","item" and"namedItem" in addition to your elements!

即使GetElementsByTagname应该返回一个节点列表,大多数浏览器也会返回一个HTMLCollection:https://developer.mozilla.org/en/dom/document.getelementsbytagname


使用for(myarray中的var i),您也可以循环对象,我将包含键名,您可以通过myarray[i]访问属性。另外,您将添加到对象中的任何方法也将包含在循环中,例如,如果您使用任何外部框架(如jquery或原型),或者如果您直接将方法添加到对象原型中,那么在某一点上,我将指向这些方法。


我看到过使用对象、原型和数组的"for each"的问题

我的理解是for-each用于对象的属性而不是数组


根据jspef,一个更短、最好的代码是

1
2
3
4
keys  = Object.keys(obj);
for (var i = keys.length; i--;){
   value = obj[keys[i]];// or other action
}

因为数组上的In循环与原型不兼容。如果您认为将来可能需要使用该库,那么坚持使用循环是有意义的。

http://www.prototypejs.org/api/array


如果你真的想加速你的代码,那怎么办?

1
for( var i=0,j=null; j=array[i++]; foo(j) );

它有点像for语句中的while逻辑,而且不那么多余。此外,火狐还有array.foreach和array.filter。


使用array().foreach循环利用并行性


for(;;)用于数组:[20,55,33]

for..in表示对象:x:20,y:55:z:33


for-in语句允许循环遍历对象所有属性的名称。不幸的是,它还循环遍历通过原型链继承的所有成员。当感兴趣的是数据成员时,这样做会产生不良的副作用,即提供方法函数。


小心!!!!我在Mac OS中使用的是Chrome22.0,我对for-each语法有问题。

我不知道这是浏览器问题、javascript问题还是代码中的一些错误,但这很奇怪。在物体外,它工作得很好。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var MyTest = {
    a:string ="a",
    b:string ="b"
};

myfunction = function(dicts) {
    for (var dict in dicts) {
        alert(dict);
        alert(typeof dict); // print 'string' (incorrect)
    }

    for (var i = 0; i < dicts.length; i++) {
        alert(dicts[i]);
        alert(typeof dicts[i]); // print 'object' (correct, it must be {abc:"xyz"})
    }
};

MyObj = function() {
    this.aaa = function() {
        myfunction([MyTest]);
    };
};
new MyObj().aaa(); // This does not work

myfunction([MyTest]); // This works

两者之间有一个重要的区别。for-in迭代对象的属性,因此当案例是一个数组时,它将不仅迭代其元素,还迭代其具有的"remove"函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
for (var i = 0; i < myArray.length; i++) {
    console.log(i)
}

//Output
0
1

for (var i in myArray) {
    console.log(i)
}

// Output
0
1
remove

您可以将for与if(myArray.hasOwnProperty(i))一起使用。不过,在对数组进行迭代时,我始终希望避免这种情况,只使用for(;;)语句。


虽然两者非常相似,但有一个微小的区别:

1
2
3
4
5
6
7
var array = ["a","b","c"];
array["abc"] = 123;
console.log("Standard for loop:");
for (var index = 0; index < array.length; index++)
{
  console.log(" array[" + index +"] =" + array[index]); //Standard for loop
}

在这种情况下,输出为:

回路标准:

数组〔0〕=a

数组〔1〕=B

数组〔2〕=C

1
2
3
4
5
console.log("For-in loop:");
for (var key in array)
{
  console.log(" array[" + key +"] =" + array[key]); //For-in loop output
}

在这种情况下,输出为:

输入回路:

数组〔1〕=B

数组〔2〕=C

数组〔10〕=D

数组[abc]=123