JavaScript:.forEach()和.map()之间的区别

244

我知道有很多类似的话题。 我知道基础知识:.forEach() 操作原始数组,.map() 操作新数组。

在我的情况下:

function practice (i){
    return i+1;
};

var a = [ -1, 0, 1, 2, 3, 4, 5 ];
var b = [ 0 ];
var c = [ 0 ];
console.log(a);
b = a.forEach(practice);
console.log("=====");
console.log(a);
console.log(b);
c = a.map(practice);
console.log("=====");
console.log(a);
console.log(c);

这是输出结果:

[ -1, 0, 1, 2, 3, 4, 5 ]
=====
[ -1, 0, 1, 2, 3, 4, 5 ]
undefined
=====
[ -1, 0, 1, 2, 3, 4, 5 ]
[ 0, 1, 2, 3, 4, 5, 6 ]

我不明白为什么使用practice会使b的值变成undefined
如果这是一个愚蠢的问题,我很抱歉,因为我在这种语言方面还很新,到目前为止找到的答案都没有让我满意。


116
很简单:.map返回一个新数组,而.forEach不返回任何内容。基本上,如果你想获得前一个数组的修改形式,你使用.map,如果不想要,就用.forEach - Sebastian Simon
1
@Xufox - 在创建新主题之前,我阅读了这个话题,但是答案没有让我满意。 - DzikiChrzan
1
不要只是说它没有满足你。它到底没有回答你的问题(你读了所有的答案吗?)?你的具体问题是什么,不在提出的重复目标范围内? - Sebastian Simon
1
@Xufox 那个问题涉及到自己实现的函数,不是关于标准化 ES5 函数的。 - poke
显示剩余3条评论
18个回答

333

它们不是同一种东西。让我解释一下它们的区别。

forEach: 这个方法遍历一个列表并对每个列表成员应用一些带有副作用的操作(例如:将每个列表项保存到数据库中)并且不返回任何值。

map: 这个方法遍历一个列表,转换该列表的每个成员,并返回具有相同大小的另一个列表,其中包含转换后的成员(例如:将字符串列表转换为大写字母)。 它不会改变调用它的数组(尽管回调函数可能会这样做)。

参考资料

Array.prototype.forEach() - JavaScript | MDN

Array.prototype.map() - JavaScript | MDN


6
映射函数返回列表,而forEach函数则不返回。好的。 - Ashad Nasim
1
如果你遇到一个代码库使用 .map 而不是 .forEach,需要记住的一件事是:IE <=10 不支持 .forEach,因此常用的解决方法是使用 .map 代替。 - devqon
你确定 forEach 会修改原始数组吗? - johny why
@johnywhy 在答案中哪里提到了这一点? - Unmitigated

104
  • Array.forEach “对数组的每个元素执行一次提供的函数。”

  • Array.map “返回一个由原数组中的每个元素调用一个指定方法后的返回值组成的新数组。”

因此,forEach 实际上并没有返回任何值。它只是为每个数组元素调用函数,然后就完成了。因此,您在该调用的函数中返回的任何内容都会被简单丢弃。

另一方面,map 同样为每个数组元素调用函数,但不同于舍弃其返回值,它将捕获它并构建一个由这些返回值组成的新数组。

这也意味着您可以在使用forEach的任何地方使用map,但仍然不应该这样做,以免无目的地收集返回值。如果您不需要它们,则不收集它们更有效率。


需要注意的是:在2015年,可以争论forEachmap“更有效率”,特别是如果需要一个polyfill来支持旧浏览器(IE8或9)上的forEach。您不需要将map的返回值分配给任何变量;当map的返回值未被分配时,它的返回值应该会在map返回后立即被垃圾回收。 - cowbert
4
即使某些东西被立即垃圾回收,这并不意味着你没有受到必要的分配所影响。因此,“forEach”在概念上仍然更高效,更适用于不需要收集结果的任务。我不知道你怎么样,但在2015年,我不再开发IE8了(顺带一提,它也不支持“map”);而IE9+支持“forEach”。实际上,在我的回答一个月后,微软终止了对那些浏览器的支持。 - poke
forEach和map是否保证以相同的顺序处理元素? - Quentin 2
1
@Quentin2 是的,还有,这两个函数都是同步的,所以 mapforEach 调用只会在整个数组被循环遍历并且每个回调函数都被调用后才会返回。 - poke
@poke "forEach在概念上仍然更有效率" -- 有人有支持这个说法的统计数据吗? - johny why
显示剩余2条评论

80
forEach() map()
功能 对数组中的每个元素执行给定操作 在每个元素的“副本”上执行给定的“转换”,并返回一个包含转换后的元素的新数组,原始数组不变。
返回值 返回undefined 返回一个包含转换后元素的新数组,原始数组不变。
推荐使用场景和示例 对每个元素执行非转换处理。

例如,保存所有元素到数据库中。
获取包含对数组中每个元素进行某些处理的输出的数组。

例如,获取数组中每个字符串的长度的数组。

forEach() 示例

chars = ['Hello' , 'world!!!'] ;
    
var retVal = chars.forEach(function(word){
  console.log("Saving to db: " + word) 
})
  
console.log(retVal) //undefined

map()示例

 chars = ['Hello' , 'world!!!'] ;
    
 var lengths = chars.map(function(word){
   return word.length
 }) 
    
 console.log(lengths) //[5,8]


26

15

性能分析 当数组中的元素数量增加时,for循环比map或foreach执行速度更快。

let array = [];
for (var i = 0; i < 20000000; i++) {
  array.push(i)
}

console.time('map');
array.map(num => {
  return num * 4;
});
console.timeEnd('map');


console.time('forEach');
array.forEach((num, index) => {
  return array[index] = num * 4;
});
console.timeEnd('forEach');

console.time('for');
for (i = 0; i < array.length; i++) {
  array[i] = array[i] * 2;

}
console.timeEnd('for');


3
这是我电脑上的结果:map: 1642毫秒 forEach: 885毫秒 for: 748毫秒 - Flavio Vilante
1
这个测试并不是非常科学的。需要测试它们都做同样的事情。map正在构建一个数组,foreach正在原地编辑一个数组,而for循环也在原地修改另一个数组。当我修改测试以实际做同样的事情时,map比foreach更快。 - Anther
3
针对“我需要对每个数组元素做些什么,我应该使用什么?”这个问题,我认为在此情境下使用时具有科学性。如果要进行所有操作的直接比较,你是正确的,但对于那些询问 map 是否比 forEach 更快只是用于循环的人来说,这是一个有价值的答案。 - Deef
@Anther赢得了这场辩论。我来到这个页面想知道是否可以在不牺牲性能的情况下使用map代替forEach。如果Anther的结果准确,答案是“是”。 - johny why

10

map 返回一个新的数组。

forEach 没有返回值。

这就是它们之间的本质区别。这里的大多数其他答案都有效地表达了这一点,但方式更加复杂。


9

forEach: 如果你想对一个数组中的元素执行某个操作,你可以使用forEach,它与使用for循环相同。但是,这种方法并不会输出结果,只是循环遍历元素。

map: 如果你想对一个数组中的元素执行某个操作,并且还想将操作的结果存储在一个新的数组中,那么可以使用map方法。这类似于一个函数内部的for循环,在每次迭代之后返回结果。

希望这能帮到你。


9

forEach() :

  • 返回值:undefined

  • 调用方法后,原始数组不会被修改

  • 方法调用结束后,新的数组不会被创建


map() :

  • 返回值:新数组,其中包含在调用提供的函数对调用数组中的每个元素进行操作后得到的结果。

  • 调用方法后,原始数组不会被修改

  • 方法调用结束后,新的数组会被创建


结论:

由于 map 创建了一个新数组,如果不使用返回的数组,则使用它是反模式;相反应该使用 forEach 或 for-of。


根据阅读此页面,似乎使用.map没有任何缺点。它可以少打几个字符,循环速度至少与.forEach一样快,然后我只需要记住一个方法。 - johny why

6
区别在于它们返回的内容不同。执行后:
arr.map()

返回由处理函数产生的元素数组; 而:

arr.forEach()

返回未定义。


4

forEach()和map()的区别

forEach()仅循环遍历元素。它抛弃返回值并始终返回undefined。该方法的结果不会给我们一个输出。

map()循环遍历元素,通过迭代主数组分配内存并存储返回值。

示例:

   var numbers = [2,3,5,7];

   var forEachNum = numbers.forEach(function(number){
      return number
   })
   console.log(forEachNum)
   //output undefined

   var mapNum = numbers.map(function(number){
      return number
   })
   console.log(mapNum)
   //output [2,3,5,7]

map()比forEach()更快


你怎么知道mapforEach更快? - johny why

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接