函数式编程 2
webkong
# 函数式编程 2
- 尾调用优化 PTC
- 闭包
- 容器 、Functor
- 错误处理、Either、AP、IO
- Monad
# 一、高阶函数
函数当参数,把传入的函数做一次封装,然后返回这个封装函数,达到更高层次的抽象
const add = (a, b) => a + b;
function math(fn, arg) {
return fn(arg[0], arg[1]);
}
math(add, [1, 2]); //3
1
2
3
4
5
6
2
3
4
5
6
- 他是一个函数,是一等公民
- 以一个函数作为参数
- 以一个函数作为返回结果
# 二、尾调用优化 PTC
☞ 函数内部最后的一个调用操作
- 递归:函数调用自身
- 尾递归:尾调用自身
🐯 递归需要保存大量的调用记录(深度和位置信息),很容易发生栈溢出错误
🌂为什么会栈溢出?➡️ 不断根据记录的信息,跳回上一层计算,然后再跳回更高一层,直到最后一层。 在 CPU 计算和内存会消耗很多,深度过大时会 栈溢出 ☁️
🐯 如果使用尾递归优化,姜帝圭变为循环,那就只用保存一个调用记录,就不会发生栈溢出
尾递归调用优化我们把上一次的执行结果作为返回值就不会有堆栈调用记录了
function sum(x, total) {
if (x === 1) {
return x + total;
}
return sum(x - 1, x + total);
}
sum(5, 0);
sum(4, 5);
sum(3, 9);
sum(2, 12);
sum(1, 14);
15;
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 尾递归问题
🤙 浏览器没有做尾递归调用优化,因为怕影响 js 执行顺序,找不到执行记录
🐿 尾递归的判断标准是函数运行「最后一步」是否调用自身,而不是最后一行
# 解决递归问题
- while
- reduce
- 蹦床函数相当于就是把每一次的递归铺平
function trampoline(f) {
while (f && f instanceof Function) {
f = f();
}
return f;
}
1
2
3
4
5
6
2
3
4
5
6
# 三、闭包
🐴 Maybe、Either、IO 这三个函子,在链式调用、惰性求值、错误捕捉、输入输出 中都发挥着巨大作用
❓ 如何处理嵌套的函子? ❓ 如何处理一个由非纯的或者异步的操作序列?
# 四、Monad
是一种设计模式,表示讲一个运算过程,通过函数拆解成互相连接的多个步骤
你只要提供下一步运算所需的函数,整个运算就会自动运行下去
Promise 就是 Monad,Monad 让我们避开了嵌套地狱
# 五、常用库
- Rxjs
- cyclejs,基于 Rxjs
- lodashjs、lazy
- underscore
- ramdajs