JavaScript 函数式编程
函数对于外部状态的依赖 是造成系统复杂性大大提高的主要原因, 让函数尽可能地纯净
优点: 声明式, 专注业务, 降低复杂度, 可缓存(惰性)
依赖特性: 高阶函数, 闭包
尾递归
尾调用指某函数最后一步调用另一函数。尾调用自身称尾递归
尾调用优化指尾递归不保存上层变量, 只占用一个栈帧, 由引擎实现
function tailFactorial(n, total) {
if (n === 1) return total;
return tailFactorial(n - 1, n * total);
}
tailFactorial(5, 5);
柯里化
是偏函数的实现
用部分参数生成函数, 减少参数, 可分步求值(惰性求值)
function f(n) {
return n * n;
}
function g(n) {
return n * 2;
}
function pipe(f, g) {
return function() {
return f.call(null, g.apply(null, arguments));
};
}
var fn = pipe(f, g);
fn(5); // 对比 f(g(5))
反柯里化
Function.prototype.uncurry = function() {
// this 指调用uncurry的函数, 设这个函数是 fn
// 返回的函数是`fn.call`
return this.call.bind(this);
};
// 变量 `push` 实际为 `Array.prototype.push.call`
var push = Array.prototype.push.uncurry();
var arr = [];
// 以下调用实际为 Array.prototype.push.call(..., ...)
push(arr, 1);
push(arr, 2);
Point Free
不显式指定调用参数, 直接拿来用
是单一职责的纯函数实现
var toUpperCase = word => word.toUpperCase();
var split = x => str => str.split(x);
var f = compose(split(" "), toUpperCase);
f("abcd efgh");
Monad
var fs = require("fs");
var _ = require("lodash");
// Functor 是一种容器类型
class Functor {
constructor(val) {
this.val = val;
}
// 定义了这个方法: 接收 含值容器 和 函数, 函数处理 容器的值, 返回另一个 含值容器
// (a -> b) -> functor a -> functor b
map(f) {
return new Functor(f(this.val));
}
}
// Monad 定义了这样的方法: 接收 含值容器 和 函数, 函数处理 容器的值, 返回另一个 含值容器
// monad a -> (a -> monad b) -> monad b
class Monad extends Functor {
join() {
return this.val;
}
// 如果有嵌套容器, 即 f 返回容器, 可以取出, 保证永远返回单层容器
flatMap(f) {
return this.map(f).join();
}
}
var compose = _.flowRight; // function compose(f, g) { return f(g()) }
// IO 和 脏操作 打交道
// 是 Applicative
class IO extends Monad {
// val是最初的脏操作
static of(val) {
return new IO(val);
}
// Applicative 的方法定义为这样: 接收 含函数的容器 和 函数, 返回另一个 含函数的容器
map(f) {
return IO.of(compose(f, this.val));
}
}
var readFile = function(filename) {
return IO.of(function() {
return fs.readFileSync(filename, "utf-8");
});
};
var print = function(x) {
console.log("p");
return IO.of(function() {
return x + " 函数式";
});
};
const result = readFile("./txt") // 返回容器 IO
// flatMap 返回的是函数 compose
.flatMap(print);
console.log(result().val());