函数柯理化的表现是:把一个需要传入多个变量的函数变为多个嵌套函数,并且内层函数会调用上层函数的变量。
现在有一个简单的add
函数:
function add(x, y) {
return x + y;
}
console.log(add(1, 2)); // 3
将其改为柯理化函数
function add2(x) {
return function (y) {
return x + y;
}
}
console.log(add2(1)(2)); // 3
从上面的例子可以看出,柯理化很像现在流行的组件化开发模式,将多个函数模块组合起来,得到一个新的函数。
柯理化函数的核心是闭包,因为闭包,所以内层函数才能够保留父作用域中的变量。
通用柯理化函数
1. 版本一
创建一个通用的柯理化函数的方式如下:
function currying(fun) {
var args = Array.prototype.slice.call(arguments, 1);
return function () {
var _args = args.concat(Array.prototype.slice.call(arguments));
return fun.apply(null, _args);
}
}
可以看到,currying
函数将除了第一个fn变量,将其他参数变量都赋值在args
变量中,然后将其合并在返回函数的变量参数中,给返回函数使用。
现在,利用currying
改造一个支持多个入参的add
函数(采用ES6语法):
// 支持多个入参
function add(...vals) {
return vals.reduce((pre, val) => {
return pre + val;
});
}
var newAdd = currying(add, 1, 2, 3);
console.log(newAdd(4, 5, 6)); // 21
这种方式创建的柯理化函数只能调用一次。
2. 版本二
再实现一种柯理化工厂函数,可以多次调用,最后统一求值。
function currying(fn) {
var args = Array.prototype.slice.call(arguments, 1);
return function () {
if (arguments.length === 0) {
return fn.apply(this, args);
}
else {
Array.prototype.push.apply(args, arguments);
return arguments.callee;
}
}
}
利用上面的currying
改造add
函数:
function add() {
var vals = Array.prototype.slice.call(arguments);
return vals.reduce((pre, val) => {
return pre + val;
});
}
var newAdd = currying(add, 1, 2, 3);
newAdd(4, 5);
newAdd(6, 7);
console.log(newAdd()); // 28
这种方式,把每次函数调用的参数都存储起来,如果已无参形式调用,说明记录结束,需要做最终计算。
小结
总之,柯理化就是利用模块化思想处理多参函数,通过组合函数减少每个函数的入参数量,从而提高代码的可阅读性及可维护性。