尾递归解决的是栈的记忆成本,更好防止堆栈溢出。
递归在两种情况下会挂:一是没有结束条件;二是堆栈内存超过了最大限制。
1、柯里化
柯里化是一种“预加载”函数的方法,通过传递较少的参数,得到一个已经记住了这些参数的新函数,某种意义上讲,这是一种对参数的“缓存”,是一种非常高效的编写函数的方法。
2、高阶函数
函数当参数,把传入的函数做一个封装,然后返回这个封装函数,达到更高程度的抽象。
3、尾调用优化
指函数内部的最后一个动作是函数调用。该调用的返回值,直接返回给函数。
函数调用自身,成为递归。如果尾调用自身,就称为尾递归。
递归需要保存大量的调用记录,很容易发生栈溢出错误,如果使用尾递归优化,将递归变为循环,那么只需要保存一个调用记录,这样就不会发生栈溢出错误了。
4、范畴与容器
函子(Functor): 用于将一个范畴转成另一个范畴。
函子是函数式编程里最重要的数据类型,也是基本的运算单位和功能单位。它首先是一种范畴,也就是说,是一个容器,包含了值和变形关系。比较特殊的是,它的变形关系可以依次作用于每一个值,将当前容器变形成另一个容器。
任何具有 map 方法的数据结构,都可以当作函子的实现。
函数式编程一般约定,函子有一个 of 方法,用来生成新的容器。函子的标志就是容器具有 map 方法。该方法将容器里面的每一个值,映射到另一个容器。
5、Either 函子
内部有两个值:左值和右值。右值是正常情况下使用的值,左值是右值不存在时使用的默认值。
Left 和 Right 唯一的区别就在于 map 方法的实现,Right.map 的行为和我们之前提到的 map函数一样。但是 Left.map 就很不同了:它不会对容器做任何事情,只是很简单地把这个容器拿进来又扔出去。这个特性意味着,Left 可以用来传递一个错误消息。
6、ap函子
函子里面包含的值,完全可能是函数。我们可以想象这样一种情况,一个函子的值是数值,另一个函子的值是函数。
ap 是 applicative(应用)的缩写。凡是部署了ap
方法的函子,就是 ap 函子。
class Ap extends Functor {
ap(F) {
return Ap.of(this.val(F.val));
}
}
注意,ap
方法的参数不是函数,而是另一个函子。
7、Monad
Monad是一种设计模式,表示将一个运算过程,通过函数拆解成互相连接的多个步骤。你只要提供下一步运算所需的函数,整合运算就会自动进行下去。
Promise 就是一种 Monad 。
Monad 让我们避开了嵌套地狱,可以轻松地进行深度嵌套的函数式编程,比如 IO和其它异步任务
JavaScript函数式编程(一)
JavaScript函数式编程(二)
JavaScript函数式编程(三)