JavaScript-myArray.foreach 与 for 循环的细微差别

我见过很多建议使用的问题:

for (var i = 0; i < myArray.length; i++){ /* ... */ }

而不是:

for (var i in myArray){ /* ... */ }

对于数组,由于迭代不一致(看这里)。


然而,我似乎找不到任何更喜欢面向对象循环的东西:

myArray.forEach(function(item, index){ /* ... */ });

这对我来说更直观。

对于我目前的项目,IE8兼容性是重要的,我正在考虑使用 Mozilla 的填充物,但我不是100% 肯定这将如何工作。

  • 现代浏览器的标准 for 循环(上面的第一个例子)和 Array.Prototype.foreach 实现之间有什么区别吗?
  • 现在的浏览器实现和上面提到的 Mozilla 实现(特别是 IE8)有什么不同吗?
  • 性能不是问题,只是迭代属性的一致性问题。
43859 次浏览

The most substantive difference between the for loop and the forEach method is that, with the former, you may break out of the loop. You can simulate continue by simply returning from the function passed to forEach, but there is no way to stop looping altogether.

Aside from that, the two accomplish effectively the same functionality. Another minor difference involves the scope of the index (and all containing variables) in the for loop, due to variable hoisting.

// 'i' is scoped to the containing function
for (var i = 0; i < arr.length; i++) { ... }


// 'i' is scoped to the internal function
arr.forEach(function (el, i) { ... });

However, I find that forEach is much more expressive—it represents your intent to iterate through each element of an array, and it provides you with a reference to the element, not just the index. Overall, it mostly comes down to personal taste, but if you can use forEach, I would recommend using it.


There are a few more substantial differences between the two versions, specifically regarding performance. In fact, the simple for loop performs considerably better than the forEach method, as demonstrated by this jsperf test.

Whether or not such performance is necessary for you is up to you to decide, and in most cases, I would favor expressiveness over speed. This speed difference is likely due to the minor semantic differences between the basic loop and the method when operating on sparse arrays, as noted in this answer.

If you don't need the behavior of forEach and/or you need to break out of the loop early, you can use Lo-Dash's _.each as an alternative, which will also work cross-browser. If you're using jQuery, it also provides a similar $.each, just note the differences in arguments passed to the callback function in each variation.

(As for the forEach polyfill, it should work in older browsers without problems, if you choose to go that route.)

It is suggested by many developers (e.g. Kyle Simpson) to use .forEach to indicate that the array will have a side effect and .map for pure functions. for loops fit well as a general-purpose solution for known number of loops or any other case that doesn't fit as it is easier to communicate because of its broad support across the majority of programming languages.

e.g.

/* For Loop known number of iterations */
const numberOfSeasons = 4;
for (let i = 0; i < numberOfSeasons; i++) {
//Do Something
}


/* Pure transformation */
const arrayToBeUppercased = ['www', 'html', 'js', 'us'];
const acronyms = arrayToBeUppercased.map((el) => el.toUpperCase));


/* Impure, side-effects with .forEach */
const acronymsHolder = [];
['www', 'html', 'js', 'us'].forEach((el) => acronymsHolder.push(el.toUpperCase()));


Convention wise, this seems best, however the community hasn't really settled on a convention on the newer iteration protocol for in loops. Generally, I think it's a good idea to follow the FP concepts that the JS community seems to be open to adopting.

You can use your custom foreach function which will perform much better then Array.forEach

You should add this once to your code. This will add new function to the Array.

function foreach(fn) {
var arr = this;
var len = arr.length;
for(var i=0; i<len; ++i) {
fn(arr[i], i);
}
}


Object.defineProperty(Array.prototype, 'customForEach', {
enumerable: false,
value: foreach
});

Then you can use it anywhere like the Array.forEach

[1,2,3].customForEach(function(val, i){


});

The only difference it is 3 times faster. https://jsperf.com/native-arr-foreach-vs-custom-foreach

UPDATE: In new Chrome version the performance of .forEach() was improved. However, the solution can give the additional performance in other browsers.

JSPerf