JavaScript for ... in vs for

时间:2008-10-28 10:42:10

标签: javascript

你认为for in和for循环有很大的不同吗?您更喜欢使用什么样的“for”以及为什么?

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

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

所以我们可以迭代:

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

for (var i in myArray)

我没有看到很大的不同。有任何性能问题吗?

23 个答案:

答案 0 :(得分:543)

选择应基于最能理解的习语。

使用以下代码迭代数组:

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

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

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

除非你有惊天动地的原因,否则请坚持既定的使用方式。

答案 1 :(得分:160)

Douglas Crockford建议JavaScript: The Good Parts(第24页)避免使用for in语句。

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

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

for (var name in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, name)) {
        // DO STUFF
    }
}

答案 2 :(得分:62)

仅供参考 - jQuery用户


jQuery的each(callback)方法默认使用for( ; ; )循环,如果长度为for( in ),则仅使用undefined

因此,我认为使用此功能时可以安全地假设正确的顺序。

示例

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

使用它的缺点是,如果你正在做一些非UI逻辑,你的功能将不太容易移植到其他框架。 each()函数最好保留用于jQuery选择器,否则for( ; ; )可能是可取的。


答案 3 :(得分:29)

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

例如:

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

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

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

然而,除非你的阵列是巨大的,否则你不断循环它们都足够快。我严重怀疑阵列循环是你项目(或任何其他项目)的瓶颈

答案 4 :(得分:26)

请注意,原生Array.forEach方法现在是widely supported

答案 5 :(得分:24)

更新了2012年的答案所有主流浏览器的当前版本 - Chrome,Firefox,IE9,Safari和Opera支持ES5的原生array.forEach。

除非你有理由本机支持IE8(记住ES5-shim或Chrome框架可以提供给这些用户,这将提供一个合适的JS环境),简单地使用该语言的正确语法更简洁:

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

Full documentation for array.forEach() is at MDN.

答案 6 :(得分:14)

使用forEach跳过原型链

只是@nailer's answer above的快速附录,使用带有Object.keys的forEach意味着您可以避免迭代原型链而无需使用hasOwnProperty。

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]);
});

答案 7 :(得分:14)

我认为您应该根据需要选择迭代方法。我建议你实际上不要永远循环使用Array结构的原生for in。正如Chase Seibert刚才指出的那样,的速度要慢一些,与原型框架不兼容。

有一个很棒的benchmark on different looping styles that you absolutely should take a look at if you work with JavaScript。不要做早期优化,但是你应该把这些东西留在脑后。

我会使用for in来获取对象的所有属性,这在调试脚本时特别有用。例如,当我探索不熟悉的对象时,我喜欢使用这条线:

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

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

答案 8 :(得分:13)

当数组稀疏时,两者不一样。

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

答案 9 :(得分:7)

这是我做过的事。

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元素列表)

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';
  }
});

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

答案 10 :(得分:6)

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

如果您只想要当前项目,请使用foreach。

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

我从未注意到性能差异。我一直等到遇到性能问题才担心它。

答案 11 :(得分:4)

使用 for(var i in myArray),你也可以遍历对象, i 将包含密钥名称,你可以通过 myArray访问该属性[ I] 。另外,您将添加到对象中的任何方法也将包含在循环中,即,如果您使用任何外部框架(如jQuery或原型),或者如果您直接向对象原型添加方法,则 i 将指向这些方法。

答案 12 :(得分:4)

小心!

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

https://developer.mozilla.org/en/DOM/HTMLCollection

如果你使用foreach语句(你的列表中的var i),它将在大多数浏览器中返回HTMLCollection的保护和方法!

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应返回NodeList,大多数浏览器都会返回HTMLCollection: https://developer.mozilla.org/en/DOM/document.getElementsByTagName

答案 13 :(得分:3)

如果您真的想加快代码速度,那该怎么办?

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

它有点在for语句中使用while逻辑,并且它不那么冗余。另外firefox有Array.forEach和Array.filter

答案 14 :(得分:3)

我看到使用对象,原型和数组的“for each”存在问题

我的理解是for each用于对象和NOT数组的属性

答案 15 :(得分:3)

对于Arrays上的in循环与Prototype不兼容。如果您认为将来可能需要使用该库,那么坚持使用for循环是有意义的。

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

答案 16 :(得分:3)

根据jsperf的更短和最好的代码是

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

答案 17 :(得分:1)

使用Array()。forEach循环来利用并行性

答案 18 :(得分:1)

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

for..in 适用于对象:{x:20,y:55:z:33}

答案 19 :(得分:0)

小心!!! 我在Mac OS中使用Chrome 22.0,我对每种语法都有问题。

我不知道这是一个浏览器问题,javascript问题还是代码中的一些错误,但它非常奇怪。在对象之外它完美地运作。

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

答案 20 :(得分:0)

两者之间存在重要差异。 for-in遍历对象的属性,因此当case是一个数组时,它不仅会迭代它的元素,还会遍历它所拥有的“remove”函数。

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-in与if(myArray.hasOwnProperty(i))一起使用。但是,当迭代数组时,我总是希望避免这种情况,只使用for(;;)语句。

答案 21 :(得分:0)

虽然两者非常相似,但存在细微差别:

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
}

在这种情况下输出为:

循环标准:

ARRAY [0] = A

ARRAY [1] = B

ARRAY [2] = C

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

虽然在这种情况下输出是:

FOR-IN LOOP:

ARRAY [1] = B

ARRAY [2] = C

ARRAY [10] = D

ARRAY [ABC] = 123

答案 22 :(得分:0)

for in语句允许循环遍历对象的所有属性的名称。不幸的是,它还遍历通过原型链继承的所有成员。当兴趣在数据成员中时,这具有提供方法功能的不良副作用。