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页),以避免使用
如果使用
除了属性之外的所有内容都可以用
1 2 3 4 5 | for (var name in obj) { if (Object.prototype.hasOwnProperty.call(obj, name)) { // DO STUFF } } |
仅供参考-jquery用户
jquery的
因此,在使用这个函数时,可以安全地假定正确的顺序。
例子:
1 2 3 4 | $(['a','b','c']).each(function() { alert(this); }); //Outputs"a" then"b" then"c" |
使用这种方法的缺点是,如果您正在执行一些非UI逻辑,那么您的函数就不太容易移植到其他框架。
根据您使用的循环类型和浏览器的不同,会存在性能差异。
例如:
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。
我认为你应该根据自己的需要选择迭代法。我建议您实际上不要使用
对于不同的循环样式,有一个很好的基准,如果您使用JavaScript的话,您绝对应该看看。不要过早地进行优化,但是你应该把那些东西放在脑后的某个地方。
我将使用
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与
虽然两者非常相似,但有一个微小的区别:
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