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

Mic*_*wis 88 javascript arrays iterator for-loop internet-explorer-8

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

for (var i = 0; i < myArray.length; i++){ /* ... */ }
Run Code Online (Sandbox Code Playgroud)

代替:

for (var i in myArray){ /* ... */ }
Run Code Online (Sandbox Code Playgroud)

对于数组,由于迭代不一致(参见此处).


但是,我似乎无法找到任何似乎更喜欢面向对象循环的东西:

myArray.forEach(function(item, index){ /* ... */ });
Run Code Online (Sandbox Code Playgroud)

这对我来说似乎更直观.

对于我目前的项目,IE8的兼容性很重要,我正在考虑使用Mozilla的polyfill,但是我不能100%确定它是如何工作的.

  • 循环标准(上面的第一个例子)和现代浏览器的Array.prototype.forEach实现之间有什么区别吗?
  • 现代浏览器实现与上面链接的Mozilla实现之间有什么区别(特别是关于IE8)?
  • 性能不是一个问题,只是与迭代属性的一致性.

Ale*_*ing 121

for循环和forEach方法之间最实质的区别在于,对于前者,您可能break不在循环中.您可以continue通过简单地从传递给的函数返回来进行模拟forEach,但是没有办法完全停止循环.

除此之外,两者有效地实现了相同的功能.由于可变提升,另一个微小差异涉及for循环中索​​引(以及所有包含变量)的范围.

// '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) { ... });
Run Code Online (Sandbox Code Playgroud)

但是,我发现它forEach更具表现力 - 它代表了你遍历数组中每个元素的意图,它为你提供了对元素的引用,而不仅仅是索引.总的来说,它主要归结为个人品味,但如果你可以使用forEach,我会建议使用它.


两个版本之间存在一些实质性差异,特别是在性能方面.实际上,简单的for循环比该forEach方法表现得更好,正如这个jsperf测试所证明的那样.

这种表现是否对你来说是必要的取决于你自己决定,在大多数情况下,我更倾向于表达速度.这个速度差异可能是由于在稀疏阵列上操作时基本循环和方法之间的微小语义差异,如本答案中所述.

如果你不需要forEach早期的行为和/或你需要突破循环,你可以使用Lo-Dash _.each作为替代方案,它也可以跨浏览器工作.如果你正在使用jQuery,它也提供了类似的$.each,只需注意每个变体中传递给回调函数的参数的差异.

(至于forEachpolyfill,如果你选择走这条路线,它应该可以在没有问题的旧浏览器中工作.)

  • 还有一些原型方法允许你打破诸如`Array.prototype.some`,它将循环,直到你返回一个truthy值或直到它完全循环通过数组.`Array.prototype.every`类似于`Array.prototype.some`,但如果你返回一个假值,它会停止. (7认同)
  • @MarbleDaemon这种可能性非常微小,实际上是不可能的,因此可以忽略不计.用一些不兼容的版本覆盖`Array.prototype.forEach`将有可能打破那么多因为这个原因而避免它的库无论如何都无济于事. (2认同)

Sea*_*ull 12

您可以使用自定义foreach函数,它将比Array.forEach更好地执行

您应该在代码中添加一次.这将为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
});
Run Code Online (Sandbox Code Playgroud)

然后你可以像Array.forEach一样在任何地方使用它

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

});
Run Code Online (Sandbox Code Playgroud)

唯一的区别是它快了3倍.https://jsperf.com/native-arr-foreach-vs-custom-foreach

更新:在新的Chrome版本中,.forEach()的性能得到了改进.但是,该解决方案可以在其他浏览器中提供额外的性能.

JSPerf


ste*_*jay 5

许多开发人员(例如 Kyle Simpson)建议使用它.forEach来指示数组将有副作用和.map纯函数。for循环非常适合作为已知循环次数或任何其他不适合的情况的通用解决方案,因为它更容易沟通,因为它对大多数编程语言的广泛支持。

例如

/* 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()));

Run Code Online (Sandbox Code Playgroud)

按照惯例,这似乎是最好的,但是社区还没有真正确定新的迭代协议for in循环的惯例。一般来说,我认为遵循 JS 社区似乎愿意采用的 FP 概念是个好主意。