链接映射函数时,它们是否在一个循环中执行? 在JavaScript中考虑使用 MAP()/函数: [1,2].map(x => x + 1).map(x => x + 2); // [3,4]

链接映射函数时,它们是否在一个循环中执行? 在JavaScript中考虑使用 MAP()/函数: [1,2].map(x => x + 1).map(x => x + 2); // [3,4],javascript,functional-programming,functor,Javascript,Functional Programming,Functor,我想知道每个arrow函数调用是在单独的循环中执行,还是在一个循环中将函数应用于数组元素。我知道,例如在java中,这些函数将在一个循环中执行(使用Java8中的流)。在这种情况下,我们可以链接一些非终端的函数(它们返回流,我们可以调用另一个函数),但这些操作直到我们使用终端函数(如collect(),将流转换为某个集合,如数组)才会执行。因此,所有操作(映射、过滤器等)都被合并,以便它们都可以在一个循环中运行 另一方面,我们有一个JavaScript,其中我们知道Array.prototype

我想知道每个arrow函数调用是在单独的循环中执行,还是在一个循环中将函数应用于数组元素。我知道,例如在java中,这些函数将在一个循环中执行(使用Java8中的流)。在这种情况下,我们可以链接一些非终端的函数(它们返回流,我们可以调用另一个函数),但这些操作直到我们使用终端函数(如
collect()
,将流转换为某个集合,如数组)才会执行。因此,所有操作(映射、过滤器等)都被合并,以便它们都可以在一个循环中运行

另一方面,我们有一个JavaScript,其中我们知道
Array.prototype.map()
返回另一个数组,因此似乎每个
map()
调用都在单独的循环中执行。但那将是相当浪费执行时间!最简单的答案是,它都是由引擎优化的,所以函数确实是在一个循环中执行的,但我找不到任何信息表明情况如此


一个附带的问题——我们可以说Java的
是一个函子吗?看起来是这样的-它有一个映射函数,可以将集合转换为相同大小的集合并返回一个流。但另一方面,正如前面提到的,这个映射函数实际上不会修改任何东西,直到我们调用某个终端函数。

在处理函子时,你可以依靠这些定律来帮助你在看到模式时重构和优化代码

在本例中,当您使用
map(a).map(b)
时,可以将其转换为
map(compose(b,a))

使用compose将在单个循环中运行
a
,首先将其返回值传递给
b
。使用map,您将循环数组两次

const compose=(f,g)=>x=>f(g(x))
常量add1=x=>x+1
常数add2=x=>x+2
console.log(
[1,2].map(add1).map(add2)
)
console.log(
[1,2]。映射(撰写(add2,add1))
)
链接映射函数时,它们是否在一个循环中执行

[1,2].map(x=>x+1).map(x=>x+2);//[3,4]
答案是否定的,底层引擎不会进行这种优化,代码实际上是按照您看到的方式执行的。不太可能是其他语言,如Haskell,其中的功能(如)是其成功的关键部分


但是,这并不意味着您无法在javascript中实现类似的优化级别。:)这就是为什么我想介绍
传感器的概念,我也建议您阅读这篇文章

让我们回顾一下上面的例子, 算法的顺序是
O(2n)
, 这意味着我们对原始输入中的每个项目执行2个操作。 因此,在第一个映射和第二个映射之间会产生中间值,这在某种程度上也会严重影响性能

为什么要来这里救援?
  • 它们允许您通过分离关注点和使用小型专用单用途函数来保持相同的可读性级别
  • 应用捷径融合优化
const算法=R.compose(
R.map(R.inc.),
R.map(R.multiply(2)),
);
常数fn=R.into([],算法);
console.log(
fn([1,2,3,4]),
);

什么会让你相信它的作用?在第二个Map函数能够在其上运行之前,它必须返回一个Iterable。这更多的是关于实际发生的事情——正如我所说,这似乎是在浪费执行时间,也许引擎优化了这些调用,但我真的不知道是否是这样。@fallereneaper:理论上,一个高度优化的JIT可以确定这两个映射函数都没有副作用,但由于中间函数没有使用,因此它可以将它们组合到一个操作中。也就是说,我高度怀疑即使是最新浏览器的JS引擎也会遇到如此大的麻烦;识别和优化这种情况所需的分析将是复杂的,并且可能运行时成本高昂,对于有限的用例来说,复杂的JIT优化很难证明是合理的。理论上是肯定的,但您应该能够看到将执行的映射的源代码。虽然我不是那种喜欢看到人们谈论javascript和参考Java实现的人。也就是说,地图的源文档应该告诉你发生了什么,是的,虽然浏览器端的东西可能会有点优化,但Firefox如何监控“哦,前面是一个双地图,让我们把它们融合在一起。”我喜欢将其视为所见即所得,阅读docs.Related:注意,只有在回调没有副作用或者我们不关心副作用的顺序时,这种转换才合适。原始代码将在任何第二个映射之前执行第一个映射的所有副作用,而重写将交错它们。