考虑在JavaScript中简单使用map()
函数:
[1,2].map(x => x + 1).map(x => x + 2); // [3,4]
我想知道每个箭头函数调用是在单独的循环中执行还是函数应用于一个循环中的数组元素。我知道例如在java中,这些函数将在一个循环中执行(使用Java 8中的Streams)。在这种情况下,我们可以链接一些非终端的函数(它们返回我们可以调用另一个函数的Stream),但是在我们使用终端函数(如collect()
将Stream转换为某个集合之前)不执行这些操作,像一个数组)。因此,所有操作(映射,过滤器等)都被合并,以便所有操作都可以在一个循环中运行。
另一方面,我们有一个JavaScript,我们知道Array.prototype.map()
返回另一个数组,所以看起来每个map()
调用都是在单独的循环中执行的。但这会浪费执行时间!最简单的答案是它全部由引擎优化,所以函数确实在一个循环中执行,但我找不到任何信息,就是这种情况。
一个附带问题 - 我们可以说Java的Stream
是一个函子吗?它似乎是 - 它有一个map函数,可以将集合转换为相同大小的集合并返回一个流。但另一方面,如前所述,在我们调用某个终端函数之前,这个map函数实际上并没有修改任何东西。
答案 0 :(得分:0)
在处理仿函数时,您可以依赖法律来帮助您在看到模式时重构和优化代码。
在这种情况下,当您使用map(compose(b, a))
时,可以将其转换为a
使用compose将运行b
,在单循环中首先将其返回值传递给const compose = (f, g) => x => f(g(x))
const add1 = x => x + 1
const add2 = x => x + 2
console.log(
[1,2].map(add1).map(add2)
)
console.log(
[1, 2].map(compose(add2, add1))
)
。使用地图,您将循环数组两次。
<script src="https://codepen.io/synthet1c/pen/KyQQmL.js"></script>
{{1}}
答案 1 :(得分:0)
链接映射函数时-它们是否在一个循环中执行?
[1,2].map(x => x + 1).map(x => x + 2); // [3,4]
答案是否定的,底层引擎不会进行这种优化,代码实际上按照您看到的方式执行。像Haskell这样的其他语言不太可能,其中Short cut fusion之类的功能是其成功的关键部分。
但是,这并不意味着您无法在javascript中达到类似的优化水平。 :)这就是为什么我要介绍Transducer
的概念,也建议您阅读此medium article。
因此,让我们回顾一下上面的示例,
您算法的顺序为O(2n)
,
这意味着我们在原始输入中对每个项目执行2次操作。
因此,在第一张图和第二张图之间,您会产生中间值,这在一定程度上也会严重影响性能。
const algorithm = R.compose(
R.map(R.inc),
R.map(R.multiply(2)),
);
const fn = R.into([], algorithm);
console.log(
fn([1, 2, 3, 4]),
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.js" integrity="sha512-3sdB9mAxNh2MIo6YkY05uY1qjkywAlDfCf5u1cSotv6k9CZUSyHVf4BJSpTYgla+YHLaHG8LUpqV7MHctlYzlw==" crossorigin="anonymous"></script>