JS函数式编程优化
Posted 熊敬之
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JS函数式编程优化相关的知识,希望对你有一定的参考价值。
JS引擎函数实现是及时求值,因此类似_.chain(fn).map(fn).else(g())中的g(),是会直接执行。但是逻辑上我们的想法是,如果满足Maybe为Nothing时,才执行g()。
因此,我们可以提出如下解决方案:
用函数组合子,curry(fn1, fn2, value) => value ? fn1(value) : fn2();利用lodash等函数库,额外的好处,因为函数是monoid半幺群,所以满足结合律。_.chain(range(100)]).map().filter().task(3),面对这样的链式调用,它会compose(map(), filter()), 然后再task(3),也就是只会循环满足条件3个就终止了。
函数记忆化,因为函数是纯函数,所以对特定的函数输入,必定有相同的输出。所以可以再Function.prototype上实现memorize方法,实现缓存。这里用ES6的Map结构就很容易实现了。
函数尾递归TCO,tail call optimization。将函数的递归调用放到函数定义的末尾,这样它调用时会环境只有一个函数调用的帧。ES6开始编译器开始支持,原理是当函数定义实现了尾递归时,当前函数就可以认为当前执行帧已经执行完毕了,可以进行销毁。于是尾巴递归的效率会和迭代相同。实现尾递归函数书写的奥秘在于,需要把当前函数执行的累计结果放入到函数的参数中。但是尾递归在es6已经写入规范,但是大多数版本浏览器都没有支持(基本上只有移动端ios),要使用的话,可以用Babel转化,实现运用了trampoline技术。
function tco(f) {
var value
// 初始和后续调用的路径选择
var active = false
// 实际长度为1或0,模拟了调用栈的切换
var accumulated = []
return function accumulator() {
accumulated.push(arguments)
//
if (!active) {
active = true
while (accumulated.length) {
// 1. shift执行完毕accumulated === []
// 2. f.apply执行的是新的accumulator()函数,但是由于闭包里的active已经true了
// 3. 所以只会push它的arguments,至此完成了调用栈的切换
// 4. f.apply返回undefined,但是accumulated.length === 1,继续循环
// 5. 直到f.apply返回为值,此时accumulated === [],退出循环,value为最终结果
value = f.apply(this, accumulated.shift())
}
active = false
return value
}
}
}
var sum = tco(function (x, y) {
if (y > 0) {
// 此时sum已经定义完毕,实际是accumulator
return sum(x + 1, y - 1)
} else {
return x
}
})
以上是关于JS函数式编程优化的主要内容,如果未能解决你的问题,请参考以下文章