【问题标题】:What is the big difference between forEach and map?forEach 和 map 的最大区别是什么?
【发布时间】:2016-08-08 01:26:36
【问题描述】:

这里有一些我不明白的地方。我几天前刚刚了解到的map 函数应该是一个了不起的函数,如果我找到它的用途,它将改变我编写代码的方式。但我仍然看不出它与forEach 有何不同。唯一的区别是传递给map 的函数将当前元素替换为return 值。但是forEach 也可以做到这一点,这意味着map 只是forEach 的一个不太通用的版本。

MDN 上的示例:

var numbers = [1, 4, 9];
var roots = numbers.map(Math.sqrt);
// roots is now [1, 2, 3], numbers is still [1, 4, 9]

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map

好的,很酷,我猜?

我可以用 forEach 做到这一点:

var numbers = [1, 4, 9];
var roots = numbers.forEach(function(el){el=Math.sqrt(el);});
// roots is now [1, 2, 3], numbers is still [1, 4, 9]

其他例子:

var kvArray = [{key:1, value:10}, {key:2, value:20}, {key:3, value: 30}];
var reformattedArray = kvArray.map(function(obj){ 
   var rObj = {};
   rObj[obj.key] = obj.value;
   return rObj;
});
// reformattedArray is now [{1:10}, {2:20}, {3:30}], 
// kvArray is still [{key:1, value:10}, {key:2, value:20}, {key:3, value: 30}]

我可以用forEach 做到这一点,它看起来几乎一模一样。

map 有什么好的?在 forEach 不起作用的情况下,它工作得非常好的例子是什么?

【问题讨论】:

标签: javascript functional-programming


【解决方案1】:

区别在于forEach“遍历数组”和map“遍历数组并返回结果

var numbers = [1, 4, 9];

var roots = numbers.forEach(Math.sqrt);
// roots is undefined, numbers is still [1, 4, 9]

var roots = numbers.map(Math.sqrt);
// roots is [1, 2, 3], numbers is still [1, 4, 9]

map 有什么好的?它使您的代码小而精巧,因为您不需要为内置函数定义匿名函数。

var numbers = [1, 4, 9];

var roots = [];
numbers.forEach(function(val){ roots.push( Math.sqrt(val) ); });
// roots is now [1, 2, 3], numbers is still [1, 4, 9]

在您现有的示例中证明了返回结果的价值(不是双关语)......

var kvArray = [{key:1, value:10}, {key:2, value:20}, {key:3, value: 30}];
var reformattedArray = kvArray.map(function(obj){ // <---------------- map
   var rObj = {};
   rObj[obj.key] = obj.value;
   return rObj;
});
// reformattedArray is now [{1:10}, {2:20}, {3:30}], 
// kvArray is still [{key:1, value:10}, {key:2, value:20}, {key:3, value: 30}]

var kvArray = [{key:1, value:10}, {key:2, value:20}, {key:3, value: 30}];
var reformattedArray = kvArray.forEach(function(obj){ // <---------------- forEach
   var rObj = {};
   rObj[obj.key] = obj.value;
   return rObj;
});
// reformattedArray is now undefined, 
// kvArray is still [{key:1, value:10}, {key:2, value:20}, {key:3, value: 30}]

【讨论】:

    【解决方案2】:

    地图

    map 遍历一个列表并返回一个新列表,而不更改任何其他内容。它不会更改原始列表。它没有副作用。使用map,您可以采用与原语一起使用的普通函数并提升该函数,以便它可以与这些原语的列表一起使用:

    const map = (f, xs) => xs.map(x => f(x));
    const sqr = x => x * x;
    
    let xs = [1,2,3];
    let x = 3;
    
    sqr(x); // 9
    sqr(xs); // Error
    let ys = map(sqr, xs); // [1,4,9]
    xs; // [1,2,3]
    

    该示例说明了map 如何在xs 的上下文中提升sqr,以便它可以平方xs 的元素。通过这种方式,您可以对数组重用普通函数。

    forEach

    forEach 没有结果值。没有任何结果值的函数是没有用的,除非它有一些副作用。因此forEach 必须对其迭代的元素应用副作用,以便做一些有意义的事情:

    let ys = xs.forEach(sqr); // undefined
    xs; // [1,2,3]
    // without side effects, nothing has happened
    
    const sqrWithSideEffect = (x, idx, arr) => arr[idx] = x * x; // ugly, isn't it?
    xs.forEach(sqrWithSideEffect); // 
    xs; // [1,4,9]; // side effect: destructive update of xs
    

    结论forEach 来自命令式,map 来自函数式编程。两者都代表相反的范式。所以如果你真的想了解这两个函数的差异所带来的后果,就必须了解这两种编程范式之间的差异。

    【讨论】:

      猜你喜欢
      • 2011-11-12
      • 1970-01-01
      • 2013-03-28
      • 2010-09-26
      • 2012-12-30
      • 1970-01-01
      • 2016-12-24
      • 2023-03-04
      • 2016-03-29
      相关资源
      最近更新 更多