JavaScript – 开发者都应该知道的 forEach() 和 map() 的区别

JavaScript 有一些方便的方法可以帮助我们遍历数组。最常用于迭代的两个是 Array.prototype.map() 和 Array.prototype.forEach()

但我认为它们仍然有点不清楚,特别是对于初学者来说。因为它们都进行了迭代并输出了一些东西。那么区别是什么呢?

在本文中,我们将研究以下内容:

  • 定义
  • 返回值
  • 是否能够链接其他方法
  • 可变性
  • 性能速度
  • 小结

定义

map 方法接收一个函数作为参数。然后它将参数应用于每个元素并返回一个全新的数组,其中填充了调用提供的函数的结果。

这意味着它返回一个新数组,其中包含数组每个元素的执行结果。它将始终返回相同数量的项目。


const myAwesomeArray = [5, 4, 3, 2, 1]

myAwesomeArray.map(x => x * x)

// >>>>>>>>>>>>>>>>> Output: [25, 16, 9, 4, 1]

与 map 一样,forEach() 方法接收一个函数作为参数,并对每个数组元素执行一次。但是,它不会返回像 map 这样的新数组,而是返回 undefined

const myAwesomeArray = [
  { id: 1, name: "john" },
  { id: 2, name: "Ali" },
  { id: 3, name: "Mass" },
]

myAwesomeArray.forEach(element => console.log(element.name))
// >>>>>>>>> Output : john
//                    Ali
//                    Mass

返回值

map() 和 forEach() 之间的第一个区别是返回值。forEach() 方法返回 undefined,而 map() 返回一个包含转换后元素的新数组。即使它们做同样的工作,返回值却不同。

const myAwesomeArray = [1, 2, 3, 4, 5]
myAwesomeArray.forEach(x => x * x)
//>>>>>>>>>>>>>return value: undefined

myAwesomeArray.map(x => x * x)
//>>>>>>>>>>>>>return value: [1, 4, 9, 16, 25]

是否能够链接其他方法

这些数组方法之间的第二个区别是 map() 是可链接的。这意味着你可以在对数组执行 map() 方法后附加 reduce()sort()filter() 等。

这是你不能用 forEach() 做的事情,因为你可能猜到,它返回 undefined

const myAwesomeArray = [1, 2, 3, 4, 5]
myAwesomeArray.forEach(x => x * x).reduce((total, value) => total + value)
//>>>>>>>>>>>>> Uncaught TypeError: Cannot read property 'reduce' of undefined
myAwesomeArray.map(x => x * x).reduce((total, value) => total + value)
//>>>>>>>>>>>>>return value: 55

可变性

一般来说,“mutate” 这个词意味着改变、交替、修改或变换。在 JavaScript 世界中,它具有相同的含义。

可变对象是在创建后可以修改其状态的对象。那么,forEach 和 map 的可变性呢?

根据 MDN 文档:

forEach() 不会改变调用它的数组。(但是,callback 可能会这样做)。

map() 不会改变调用它的数组(尽管 callback 可能会这样做)。

JavaScript 很奇怪。

在这里,我们看到了一个非常相似的定义,我们都知道它们都接收 callback 作为参数。那么,哪一个依赖于不变性?

在我看来,这个定义并不清楚。要知道哪个不会改变原始数组,我们首先要检查这两种方法是如何工作的。

map() 方法返回一个全新的数组,其中包含转换后的元素和相同数量的数据。对于 forEach() 的情况下,即使它返回 undefined,它也会用 callback 改变原始数组。

因此,我们清楚地看到 map() 依赖于不变性,而 forEach() 是一个 mutator 方法。

性能速度

关于性能速度,它们有点不同。但是,有关系吗?嗯,这取决于各种因素,例如你的计算机、你正在处理的数据量等等。

你可以使用下面的示例或使用 jsPerf 自行检查,看看哪个更快。

const myAwesomeArray = [1, 2, 3, 4, 5]

const startForEach = performance.now()
myAwesomeArray.forEach(x => (x + x) * 10000000000)
const endForEach = performance.now()
console.log(`Speed [forEach]: ${endForEach - startForEach} miliseconds`)

const startMap = performance.now()
myAwesomeArray.map(x => (x + x) * 10000000000)
const endMap = performance.now()
console.log(`Speed [map]: ${endMap - startMap} miliseconds`)

小结

map() 和 forEach()之间的选择将取决于你的用例。如果你计划更改、替换或使用数据,那么你应该选择 map(),因为它会返回一个包含转换后数据的新数组。

但是,如果你不需要返回的数组,请不要使用 map() – 而是使用 forEach() 甚至 for 循环。

希望这篇文章能澄清这两种方法之间的差异。感谢你阅读本文!