柯里化的概念大家应该都清楚,就是将一个接受多个参数的函数转化为接受单一参数的函数的技术。
柯里化函数:
function inspect(x) {
return (typeof x === 'function') ? inspectFn(x) :inspectArgs(x);
}
function inspectFn(f) {
return (f.name) ? f.name : f.toString();
}
function inspectArgs(args) {
Array.prototype.slice.call(arguments, 0);
return [].slice.call(args, 0).reduce(function(acc, x){
return acc += inspect(x);
}, '(') + ')';
}
function curry(fx) {
// 函数的length属性返回函数必须传入的参数个数
var arity = fx.length;
return function f1() {
var args = Array.prototype.slice.call(arguments, 0);
// 参数个数满足的处理
if (args.length >= arity) {
return fx.apply(null, args);
}
else {
// 参数个数不满足的处理
var f2 = function f2() {
var args2 = Array.prototype.slice.call(arguments, 0);
return f1.apply(null, args.concat(args2));
}
f2.toString = function() {
return inspectFn(fx) + inspectArgs(args);
}
return f2;
}
};
}
其中 f2.toString
的实现是会报错的,我已经向作者提交了PR,这段无关紧要,可以跳过不看这个 fs.toString
的实现。很显然实现curry函数的核心就是判断参数个数,然后各种使用apply函数。
接下来就可以体验curry的好处:
add = curry(function(x, y) {
return x + y;
});
const add5 = add(5);
ad5(4)
// 9
这只是一个非常小的例子,源代码还有很多例子:
add = curry(function(x, y) {
return x + y;
});
match = curry(function(what, x) {
return x.match(what);
});
replace = curry(function(what, replacement, x) {
return x.replace(what, replacement);
});
filter = curry(function(f, xs) {
return xs.filter(f);
});
map = curry(function map(f, xs) {
return xs.map(f);
});
reduce = curry(function(f, a, xs) {
return xs.reduce(f, a);
});
split = curry(function(what, x) {
return x.split(what);
});
join = curry(function(what, x) {
return x.join(what);
});
在这里我们可以看到,所有的数据参数都作为了最后一个参数,很明显这样在使用时的好处就在于,这可以成为一种预加载函数函数。
非常明显的在于这样柯里化处理函数,可以让这些函数成为底层部署的函数。