forEach和map之间有什么重大区别?

时间:2016-04-15 22:32:48

标签: javascript functional-programming

这是我不明白的事情。几天前我刚刚学到的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不起作用的情况下,它的工作原理是什么?

2 个答案:

答案 0 :(得分:4)

区别在于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}]

答案 1 :(得分: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如何在sqr的上下文中提升xs,以便它可以对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。两者都代表了对立的范式。因此,如果您真的想了解两个函数之间差异的后果,您必须了解两个编程范例之间的差异。