好吧,这更像是一个计算机科学问题,而不是一个基于特定语言的问题,但是地图操作和foreach操作之间有区别吗?或者它们只是同一个东西的不同名称?
不同.
foreach迭代列表并将一些带副作用的操作应用于每个列表成员(例如将每个操作保存到数据库中)
map迭代列表,转换该列表的每个成员,并返回另一个与转换成员相同大小的列表(例如将字符串列表转换为大写)
它们之间的重要区别在于将map
所有结果累积到集合中,而不foreach
返回任何结果.map
当你想用函数转换元素集合时,通常使用它,而foreach
只是为每个元素执行一个动作.
简而言之,foreach
用于对元素集合的每个元素应用操作,而map
用于将一个集合转换为另一个集合.
foreach
和之间有两个显着的差异map
.
foreach
对它所应用的操作没有概念上的限制,除了可能接受一个元素作为参数.也就是说,操作可能无效,可能具有副作用,可能返回值或可能不返回值.所有foreach
关心的是迭代元素集合,并对每个元素应用操作.
map
另一方面,对操作有一个限制:它期望操作返回一个元素,并且可能还接受一个元素作为参数.该map
操作迭代元素集合,对每个元素应用操作,最后将每次调用操作的结果存储到另一个集合中.换句话说,map
将一个集合转换为另一个集合.
foreach
适用于单个元素集合.这是输入集合.
map
使用两个元素集合:输入集合和输出集合.
将两种算法联系起来并不是一个错误:实际上,您可以分层次地查看这两种算法,其中map
是两种算法的特化foreach
.也就是说,您可以使用foreach
并让操作转换其参数并将其插入另一个集合中.因此,该foreach
算法是算法的抽象,概括map
.实际上,因为foreach
对它的操作没有限制,我们可以有把握地说这foreach
是最简单的循环机制,它可以做循环可以做的任何事情.map
,以及其他更专业的算法,是表达性:如果你想将一个集合映射(或转换)到另一个集合,如果你使用的map
话,你的意图比你使用时更清晰foreach
.
我们可以进一步扩展这个讨论,并考虑copy
算法:克隆集合的循环.该算法也是该算法的专业化foreach
.您可以定义一个操作,给定一个元素,将该元素插入另一个集合中.如果您使用foreach
该操作,您实际上执行了copy
算法,尽管清晰度,表现力或表现力都降低了.让我们更进一步:我们可以说这map
是一个专业化copy
,本身就是一个专业化foreach
.map
可以改变它迭代的任何元素.如果map
不更改任何元素,那么它只是复制元素,并使用副本 会更清楚地表达意图.
该foreach
算法本身可能会或可能不会有一个返回值,根据语言.例如,在C++中,foreach
返回它最初接收的操作.这个想法是操作可能有一个状态,你可能希望该操作回来检查它是如何在元素上进化的.map
也可能会或可能不会返回值.在C++中transform
(map
这里的等价物)碰巧将迭代器返回到输出容器(集合)的末尾.在Ruby中,返回值map
是输出序列(集合).因此,算法的返回值实际上是一个实现细节; 他们的影响可能是也可能不是他们的回报.
Array.protototype.map
方法&Array.protototype.forEach
都非常相似.运行以下代码:http://labs.codecademy.com/bw1/6#:workspace
var arr = [1, 2, 3, 4, 5]; arr.map(function(val, ind, arr){ console.log("arr[" + ind + "]: " + Math.pow(val,2)); }); console.log(); arr.forEach(function(val, ind, arr){ console.log("arr[" + ind + "]: " + Math.pow(val,2)); });
他们给出了完全相同的结果.
arr[0]: 1 arr[1]: 4 arr[2]: 9 arr[3]: 16 arr[4]: 25 arr[0]: 1 arr[1]: 4 arr[2]: 9 arr[3]: 16 arr[4]: 25
在这里,我只是简单地从map和forEach方法中分配了返回值的结果.
var arr = [1, 2, 3, 4, 5]; var ar1 = arr.map(function(val, ind, arr){ console.log("arr[" + ind + "]: " + Math.pow(val,2)); return val; }); console.log(); console.log(ar1); console.log(); var ar2 = arr.forEach(function(val, ind, arr){ console.log("arr[" + ind + "]: " + Math.pow(val,2)); return val; }); console.log(); console.log(ar2); console.log();
现在结果很棘手!
arr[0]: 1 arr[1]: 4 arr[2]: 9 arr[3]: 16 arr[4]: 25 [ 1, 2, 3, 4, 5 ] arr[0]: 1 arr[1]: 4 arr[2]: 9 arr[3]: 16 arr[4]: 25 undefined结论
Array.prototype.map
返回一个数组,但Array.prototype.forEach
没有.因此,您可以在传递给map方法的回调函数内操作返回的数组,然后返回它.
Array.prototype.forEach
只遍历给定的数组,这样你就可以在走数组时做你的东西了.
最"可见"的区别是,map会将结果累积到新集合中,而foreach仅针对执行本身进行.
但还有一些额外的假设:由于地图的"目的"是新的价值清单,因此执行的顺序并不重要.事实上,一些执行环境生成并行代码,甚至引入一些memoizing以避免调用重复值或者懒惰,以避免调用某些代码.
另一方面,foreach被称为副作用; 因此,顺序很重要,通常不能并行化.
简短的回答: map
并且forEach
是不同的.另外,非正式地说,map
是一个严格的超集forEach
.
龙回答:首先,让我们拿出一个行描述forEach
和map
:
forEach
迭代所有元素,在每个元素上调用提供的函数.
map
迭代所有元素,在每个元素上调用提供的函数,并通过记住每个函数调用的结果来生成转换后的数组.
在许多语言中,forEach
通常被称为公正each
.以下讨论仅使用JavaScript作为参考.它可能真的是任何其他语言.
现在,让我们使用这些功能.
forEach
:任务1:编写一个printSquares
接受数字数组的函数arr
,并打印其中每个元素的平方.
解决方案1:
var printSquares = function (arr) { arr.forEach(function (n) { console.log(n * n); }); };
map
:任务2:编写一个selfDot
接受数字数组的函数arr
,并返回一个数组,其中每个元素都是相应元素的平方arr
.
旁白:在这里,在俚语中,我们试图对输入数组进行平方.正式地说,我们正试图用自己来计算它的点积.
解决方案2:
var selfDot = function (arr) { return arr.map(function (n) { return n * n; }); };
map
的超集forEach
?您可以使用任务1和任务2map
来解决这两个任务.但是,您无法使用解决任务2.forEach
在解决方案1中,如果您只是替换forEach
为map
,则解决方案仍然有效.但是,在解决方案2中,替换map
为forEach
将破坏以前工作的解决方案.
forEach
方面map
:实现的另一种方式map
的优势是落实forEach
在以下方面map
.由于我们是优秀的程序员,我们不会沉迷于命名空间污染.我们会打电话给我们的forEach
,只是each
.
Array.prototype.each = function (func) { this.map(func); };
现在,如果你不喜欢这些prototype
废话,你可以去:
var each = function (arr, func) { arr.map(func); // Or map(arr, func); };
forEach
甚至存在?答案是效率.如果您对将数组转换为另一个数组不感兴趣,为什么要计算转换后的数组呢?只是为了转储它?当然不是!如果您不想进行转换,则不应进行转换.
因此,虽然map可用于解决任务1,但它可能不应该.因为每个人都是合适的人选.
虽然我主要与@madlep的答案达成一致,我想指出的是,map()
是一个严格的超集的forEach()
.
是的,map()
通常用于创建新数组.但是,它也可用于更改当前阵列.
这是一个例子:
var a = [0, 1, 2, 3, 4], b = null; b = a.map(function (x) { a[x] = 'What!!'; return x*x; }); console.log(b); // logs [0, 1, 4, 9, 16] console.log(a); // logs ["What!!", "What!!", "What!!", "What!!", "What!!"]
在上面的例子中,a
方便地设置a[i] === i
为i < a.length
.即便如此,它也证明了它的力量map()
.
这是官方的描述map()
.请注意,map()
甚至可能会更改调用它的数组!冰雹map()
.
希望这有帮助.
2015年11月10日编辑:增加了详细说明.