【问题标题】:Are there times when array.forEach() is better than array.map()?有时array.forEach() 比array.map() 更好吗?
【发布时间】:2019-01-25 21:07:25
【问题描述】:

在 Javascript 中,我一直在阅读关于何时在数组上使用 forEachmap 的不同文章。一般的共识似乎是,如果您只想读取数组的每个元素,请使用forEach。如果您确实想修改数据,请使用map。有些人甚至说尽可能使用map,这样更安全、更快捷。

就我而言,我想做的只是更新每个元素中的单个属性。

var arr = [{
  firstName: 'Tom',
  lastName: 'Washington',
  fullName: undefined
}, {
  firstName: 'Bill',
  lastName: 'Smith',
  fullName: undefined
}, {
  firstName: 'Jim',
  lastName: 'Jones',
  fullName: undefined
}];

// arr.forEach((person) => {
//   person.fullName = `${person.lastName}, ${person.firstName}`;
// });

var newArr = arr.map((person) => {
  return {...person, fullName: `${person.lastName}, ${person.firstName}`};
});

console.log(arr);
console.log(newArr);

我很难理解为什么map 方法更受欢迎?通过使用forEach,我正在更新数据。使用map,我正在创建一个包含所有新元素的全新数组。我知道如果您想保留原始数组,这是首选,或者如果您想对数组执行其他操作,您现在可以选择进行链接。但如果我不关心这些,为什么不首选forEach

【问题讨论】:

  • 它们有两个不同的目的。他们都迭代的事实并不是假设他们在所有情况下都同样有用或者在所有情况下都比另一个更好的理由。
  • 更安全、更快?!谁说的?不变性是函数式编程的一个概念,喜欢就跟着走,不喜欢就别走。
  • 规则很简单。如果你想得到一个新数组,就拿map,否则forEach
  • map 是函数式并提供了一个新数组,forEach 只是一种迭代方法。
  • 这个问题有点语境悖论。 “如果我不在乎好处,那又有什么关系呢?” - 答案是,它没有。你为什么问?

标签: javascript arrays foreach


【解决方案1】:

他们可能称map“更安全”,因为它遵循函数式编程模型。在函数式编程中,大多数(如果不是全部)数据是不可变的;编程是从现有数据创建新数据,而不是在原地修改它。

在您可能不是数据的唯一所有者的情况下,安全优势就会出现。如果您的函数从调用者那里接收到一个数组,则对其进行适当修改会更改调用者的数组版本,而不仅仅是您自己的(因为它们实际上是同一个数组)。如果他们也将它作为参数接收,它也会更改 他们的 调用者的数组(因为它都是同一个数组)。最终,这可能会导致 12 跳以外的人用他们的数组调用一个函数,期望它保持不变,当它被修改时感到惊讶,并且没有简单的方法来确定 什么 修改了它。 p>

虽然 JavaScript 不是一种函数式语言,但它提供了函数式范例,因此您可以以函数式风格编写代码。如果您对此保持一致,则不会发生这种意外的远距离操作,并且更容易推理您的代码。

这对图书馆来说尤其重要;使用库,您不想假设调用者没有进行功能性编程,因此通过功能性行为,您可以避免打破他们的假设的风险。

也就是说,如果您没有使用函数式样式,并且您没有创建一个库来重新分发,那么远距离操作总是有风险的,并且部分函数式对您的影响很小,因此您应该为工作选择正确的工具; forEach只读或就地修改,map创建新数组。

最后一点:理论上,map 可能会使代码更快,尽管构造了新数组。当数组保证在一个函数内创建和销毁时,JIT 优化器可以更轻松地进行生命周期分析、分析典型内容等,并且可以想象:

  1. 完全优化中间数组(五个maps 可能只会创建一个新数组)
  2. 将数组专门化为内容、长度等(可能是从外部接收的数组,但更难始终如一)

我不会指望来自 map 的此类优化(不决定在此基础上使用哪个),但实际的函数式语言从它们强制执行的不变性保证中获得了这样的好处,并且 JavaScript JIT 引擎可以利用相同的“保证”,当他们可以观察到他们在实践中得到遵守时。

【讨论】:

    【解决方案2】:

    array.forEach 简单地遍历数组,而 array.map() 正在复制该数组,为每个元素创建一个回调函数,因此您可以做一些事情喜欢:

    array.map(x => x*2)

    现在你得到一个全新的数组,每个值都乘以 2

    【讨论】:

      【解决方案3】:

      只是举个例子。

      forEach() 可能更适合您不尝试更改数组中的数据,而是只想对它做一些事情 — 例如将其保存到数据库或将其注销:

      let arr = ['a', 'b', 'c', 'd'];
      arr.forEach((letter) => {
          console.log(letter);
      });
      
      
      // a
      // b
      // c
      // d

      在更改或更改数据时,map() 可能更可取。它不仅速度更快,而且返回一个新数组。这意味着我们可以做一些很酷的事情,比如链接其他方法(map(), filter(), reduce() 等)

          let arr = [1, 2, 3, 4, 5];
          let arr2 = arr.map(num => num * 2).filter(num => num > 5);
          
          // arr2 = [6, 8, 10]

      我们在上面所做的是首先映射 arr 并将数组中的每个元素乘以 2。之后,我们过滤数组并仅保存大于 5 的元素。这给我们留下了一个最终的 @ 987654326@ 的[6,8,10]

      【讨论】:

        猜你喜欢
        • 2020-08-19
        • 2012-08-28
        • 1970-01-01
        • 1970-01-01
        • 2011-07-27
        • 1970-01-01
        • 1970-01-01
        • 2010-12-23
        • 2010-09-11
        相关资源
        最近更新 更多