柯里化
Contents
柯里化(Currying)是一种基于闭包的函数的高阶技术. 而且它不仅被用于 JavaScript, 也在其他编程语言有相同的应用.
柯里化是对函数的转换, 它是指将一个函数从可调用的 f(a, b, c) 转换为可调用的 f(a)(b)(c).
柯里化并不会调用函数, 它只对函数进行转换.
我们将创建一个辅助函数 curry(f), 该函数将对两个参数的函数 f 执行柯里化. 换句话说, 对于两个参数的函数 f(a, b) 执行 curry(f) 会将其转换为以 f(a)(b) 形式运行的函数:
// curry(f) 执行柯里化转换
function curry(f) {
return function (a) {
return function (b) {
// 此函数具有访问 a, b 参数的能力
return f(a, b);
};
};
}
function sum(a, b) {
return a + b;
}
const curriedSum = curry(sum);
const addOne = curriedSum(1);
addOne(10); // 10 + 1 = 11
实现非常简单: 只有两个包装器(wrapper).
curry(func)
的结果就是一个包装器function(a)
.- 当它被像
curriedSum(1)
这样调用时, 它的参数会被保存在词法环境中, 然后返回一个新的包装器function(b)
. - 然后这个包装器被以
2
为参数调用, 并且, 它将该调用传递给原始的sum
函数.
柯里化更高级的实现, 例如 lodash 库的 _.curry, 会返回一个包装器, 该包装器允许函数被正常调用或者以偏函数(partial)的方式调用:
function sum(a, b) {
return a + b;
}
let curriedSum = _.curry(sum); // 使用来自 lodash 库的 _.curry
curriedSum(1, 2); // 3, 仍可正常调用
curriedSum(1)(2); // 3, 以偏函数的方式调用
柯里化的目的是什么
在函数式编程里, 函数是作为“一等公民”的存在, 可以把它们存在数组里, 当作参数传递, 赋值给变量..
我们举一个实际中的例子来理解:
现在我们要对 blog 进行增、删、改、查进行一次封装, 使其统一在 BlogRequest 命名空间下方便之后进行维护
初始化一个 BlogRequest 的命名空间
export const BlogRequest = {
add: null,
del: null,
update: null,
query: null,
};
随便封装的一个 request 方法
export function request(url, data) {
return $.ajax({
url: '/api/' + url,
type: 'post',
data,
timeout: 30000,
});
}
我们使用上面的简单的 curry 函数实现 blog request 的封装
const curriedRequest = curry(request);
BlogRequest.add = curriedRequest('blog/add');
BlogRequest.del = curriedRequest('blog/del');
BlogRequest.update = curriedRequest('blog/update');
BlogRequest.query = curriedRequest('blog/query');
非常简单的实现, 现在, 我们就轻松地维护与 blog 相关的请求管理了