为什么不建议使用forEach循环


我们通常使用数组时,会通过数组自带的一些方法去循环遍历处理数据,有六种方法可用于数组迭代:forEach()map()filter()reduce()for loopfor…of循环。根据工作场景选择适合的方法尤为重要。

https://blog-1309278058.cos.ap-shanghai.myqcloud.com/23-04-01_js.png

一、回顾数组的几种方法及优劣

如上所说,其实可以用于数组循环的方法大致有七种,除了上面介绍的六种还有一个是for…in,可以枚举数组中的索引或键 但是不推荐使用它来遍历数组,因为它可能会遍历非数字属性。

forEach()

优点:

  • 用于简单的迭代、是一种简单易于阅读的方法
  • 可以使用break或continue进行流程控制

缺点:

  • 无法中止或跳过迭代。
  • 无法返回值,只能对每个元素进行操作

map()

优点:

  • 生成一个新数组,不会更改原始数组。
  • 可以返回一个具有实用价值的值,例如转换后的元素。

缺点:

  • 不适合用于计算新值的情况,因为它必须返回一个值。
  • 不适合用于修改原始数组。

**filter()
优点:

  • 可以生成一个新数组,不会更改原始数组。
  • 可以返回一个过滤后的数组,根据条件过滤元素。

缺点:

  • 不适合用于修改原始数组。
  • 对于更复杂的过滤条件,代码可能会很冗长。

reduce()
优点:

  • 可以生成一个新值,例如一个数字或一个对象。
  • 可以对数组中的元素进行自定义操作。

缺点:

  • 对于简单的迭代,代码可能会很冗长。
  • 在一些情况下,不如for循环直观。

for loop:
优点:

  • 可以直观地控制迭代。

  • 可以使用break和continue关键字进行控制流程。

  • 可以进行任何操作。

    缺点:

  • 在一些情况下,代码可能会很冗长。

  • 可能会在语法上更容易出错。

for…of循环:
优点:

  • 可以直观地控制迭代。

  • 不需要使用索引。

    缺点:

  • 无法中止或跳过迭代。

  • 无法在迭代过程中更改数组。

小结:

选择哪种迭代方法或循环结构取决于具体情况、例如,如果需要生成一个新的数组,那么map()方法可能是最好的选择。如果需要遍历数组并对每个元素执行一个函数,则可以使用forEach()方法。如果需要对数组的每个元素执行一个函数,并将结果汇总为单个值,则可以使用reduce()方法。

二、为什么单单不建议使用forEach?

1.流程控制有限,无法退出循环

可能有人想,无法退出循环的方法又不止forEach一个,遍历数组每个元素并对每个元素执行操作最快的方法是使用forEach循环。但它没有提供中断循环的方法或提前从函数返回。

如果需要对特定元素使用break 或 continue 语句。forEach 方法基本上不返回任何内容,在代码优化中,避免不必要的迭代很重要。一旦开始遍历数组,就致力于完成整个循环。不能只是根据某些条件中途返回它。这种缺乏灵活性的方法真的很头疼,尤其是使用更大的数组或更复杂的逻辑时。在这种情况下 forEach 方法可能比常规的 for 循环慢。

2.不能数据/方法链路

在jquery中有个概念叫“链式调用”、如果我有个对象数组需要过滤、对每个元素执行一个操作,然后返回一个新的数组、那无疑使用 filter 或 map 方法更加轻松,而无需将它分成两行。使用forEach不能在其之后链接其他数组的方法,需要分别链接 filter() 和 forEch() ,简直是多此一举了。

3.对async/await 不兼容

用异步代码时, forEach很明显不是明智之选。因为传递给 forEach 的回调函数不会等待每次迭代完成后再继续下一次迭代。因此,如果在回调中执行异步操作,可能会得到意想不到的结果。就我个人而言,我在使用 forEach 实现异步任务时遇到过困难。它们只是不兼容

一种解决方案是使用带有 async/await 语法的 for 循环,允许等待每次迭代完成,然后再继续下一次迭代。或者可以使用其他数组方法,如 map、reduce 或 filter,它们在异步场景中更方便使用。

4.性能方面的缺陷

某些情况下,其他迭代方法,如:for、for…of,会比forEach()方法性能消耗更高,尤其是对于大量数据的大型数组。由于函数调用和数组遍历,forEach方法 有很大的性能开销。

但在大多数情况下性能上的差异可以忽略不急,选择使用哪种方法应该更基于代码的可阅读性和可维护性去做参考使用。

与forEach()方法相比,使用for循环遍历数组能更多的控制语句块,甚至对迭代过程都是可控的、可以随意定义循环的起点和终点,这个是forEach不能实现的,有时候开发中会需要这样的场景

如果需要跳过数组中的某些元素或者需要反方向遍历数组,那它怎么比?

onst numbers = [1, 2, 3, 4, 5];
let sum = 0;

for(let i = 0; i < numbers.length; i += 1) {
  if(numbers[i] % 2 === 0) {
    continue; // 不加偶数
  }
  sum += numbers[i];
}

console.log(sum); //  9

使用for循环遍历数组数组,使用continue语句跳过任何偶数,并将剩余奇数相加求和、forEach()是无法实现的,因为它需要遍历数组中每个元素并且不提供内置方法来跳过或翻转循环。

三、总结

虽然 forEach 方法因其简单易用而被广泛使用,但有几个原因导致让我选择避免使用它,例如作用域问题、处理异步代码的困难、缺乏灵活性以及与其他循环相比性能降低方法。通过了解每种迭代方法的优点和缺点,我们开发可以为工作选择合适的工具并编写更高效和可维护的代码。

我认为归根结底,这完全取决于个人喜好,如果想编写高效的代码,则值得考虑除 forEach 之外的其他选项。


文章作者: feico
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 feico !
评论
  目录