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

JavaScript—myArray.forEach与for循环的细微差别,javascript,arrays,for-loop,internet-explorer-8,iterator,Javascript,Arrays,For Loop,Internet Explorer 8,Iterator,我看到很多问题建议使用: for (var i = 0; i < myArray.length; i++){ /* ... */ } 对于数组,由于不一致的迭代() 然而,我似乎找不到任何更喜欢面向对象循环的东西: myArray.forEach(function(item, index){ /* ... */ }); 这对我来说更直观 对于我目前的项目,IE8兼容性很重要,我正在考虑使用,但是我不能100%确定这将如何工作 标准for循环(上面的第一个示例)和现代浏览器的Arra

我看到很多问题建议使用:

for (var i = 0; i < myArray.length; i++){ /* ... */ }
对于数组,由于不一致的迭代()



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

myArray.forEach(function(item, index){ /* ... */ });
这对我来说更直观

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

  • 标准for循环(上面的第一个示例)和现代浏览器的Array.prototype.forEach实现之间有什么区别吗
  • 现代浏览器的实现与上面提到的Mozilla的实现(特别是IE8)有什么区别吗
  • 性能并不是一个很大的问题,只是迭代属性的一致性

for循环的
与forEach
方法之间最本质的区别在于,使用前者,您可以
打破循环。您可以通过简单地从传递给
forEach
的函数返回来模拟
continue
,但无法完全停止循环

除此之外,两者有效地实现了相同的功能。另一个微小的差异涉及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) { ... });
/“i”的作用域为包含函数
对于(var i=0;i
但是,我发现
forEach
更具表现力,它表示您迭代数组中每个元素的意图,并且它提供了对元素的引用,而不仅仅是索引。总体而言,这主要取决于个人品味,但如果您可以使用
forEach
,我建议您使用它


这两个版本之间还有一些实质性的差异,特别是在性能方面。事实上,简单for循环的性能远远优于
forEach
方法,如所示

你是否需要这样的表现取决于你自己,在大多数情况下,我倾向于表现力而不是速度。这种速度差异可能是由于在稀疏数组上操作时,基本循环和方法之间的语义差异较小,如中所述

如果您不需要forEach的行为和/或您需要提前打破循环,您可以使用lodash作为替代,它也可以跨浏览器工作。如果您使用的是jQuery,它还提供了类似的功能,只需注意每个变体中传递给回调函数的参数的差异


(至于
forEach
polyfill,如果你选择这样做的话,它应该可以在较旧的浏览器中正常工作。)

许多开发人员(例如Kyle Simpson)建议使用
.forEach
来表示数组将产生副作用,而对于纯函数则使用
.map
for
循环非常适合作为已知数量的循环或任何其他不适合的情况的通用解决方案,因为它在大多数编程语言中具有广泛的支持,因此更易于通信

e、 g

循环已知迭代次数的
/**/
常数numberofseasures=4;
for(设i=0;iel.toUpperCase));
/*不纯,副作用。forEach*/
const首字母缩略词sholder=[];
forEach((el)=>acronymsHolder.push(el.toUpperCase());

从约定的角度看,这似乎是最好的,但是社区还没有真正确定in
循环的更新迭代协议
的约定。一般来说,我认为遵循JS社区似乎乐于采用的FP概念是一个好主意。

您可以使用定制的foreach函数,它将比Array.foreach性能更好

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

});
您应该将其添加到代码中一次。这将向数组中添加新函数

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
});
唯一的区别是速度快了3倍

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


无法将
forEach
中断开。但是一个很大的优势是用函数创建一个新的作用域。对于polyfill,您不应该有任何问题(至少我没有遇到任何问题)。旧IE可能存在的问题不是垫片本身,而是损坏的数组构造函数/literal wrt
holes
where
undefined
以及其他损坏的方法,像
slice
hasOwnProperty
wrt到类似数组的DOM对象。我的测试和测试表明,这种填充方法符合规范(未测试MDN的填充)。并且,我想打破
for
循环,这就是为什么。“但是,我似乎找不到任何更喜欢面向对象循环的方法:”我更愿意称之为功能方式vs命令式。您可以在找到第一个匹配项后使用来打破循环。值得注意的是,库版本
每个
的行为方式与
forEach
的ECMA5规范不同,它们倾向于将所有数组视为密集数组(为了避免IE漏洞,前提是你知道)。可以是“明白了”否则。作为参考,还有一些原型方法允许您断开,例如
Array.prototype。一些
将循环,直到您返回一个真实值,或者直到它完全通过数组。
Array.prototype。每个
类似于
Array.prototype。一些
,但如果您返回一个虚假的va,则会停止如果你想的话
[1,2,3].customForEach(function(val, i){

});