一道面试题教会你实现函数的柯里化
最近在学习过程中看到一道面试题,其核心就是让我们实现一个函数的柯里化,使其可以分步接收参数,那么接下来我们就由浅入深,由简完善,一步一步实现完善一个柯里化函数。
面试题如下:
// 实现一个sum 函数,使其同时满足以下两个调用需求
sum(2, 3) // 5
sum(2)(3) // 5
什么是函数柯里化?
在计算机科学中,柯里化(英语:Currying),又译为卡瑞化或加里化,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
如何实现函数柯里化?
1.0版本
实现思路,我们要实现既可以一次性传递函数需要的参数 ,也可以分布传递参数;
function currying(fn) {
// 最简易版本的柯里化
let args = [].slice.call(arguments,1); // 获取到柯里化函数时传递过来的其他参数
return function () {
args = args.concat([...arguments]);
return fn.apply(this,args);
}
}
这样实现的柯里化可以实现第一次要柯里化某一个函数时,可以传递要柯里化的函数以及函数的部分参数,然后将剩余部分的参数放到柯里化之后返回的函数中去。
代码测试:
function add(a, b, c) {
return a + b + c
}
const sum = currying(add,1);
console.log(sum(2,3) ); // 6
console.log(sum(2)(3)); // TypeError

由此可见1.0版本只支持柯里化的时候可以接收完整参数,也可以分在柯里化函数时和柯里化得到的函数这两个地方传递参数所以不太符合面试官给我们的要求。
2.0版本
上面的思路可以理解为柯里化一次函数,但是要支持sun(2)(3)需要我们至少柯里化两次,甚至我们需要实现sum(2)(3)(4)...那该如何实现呢?
把我们1.0版本的函数拿来作为一个柯里化的辅助函数,剩余我们要考虑的就是柯里化函数的分步接受参数,我们不清楚会被分成多少部分,所以一定要用到递归。
function sub_currying(fn) {
let args = [].slice.call(arguments, 1);
return function () {
args = args.concat([...arguments]);
return fn.apply(this, args)
}
}
function currying(fn) {
let length = fn.length // 一个函数的length属性可以拿到这个函数接受几个参数,用以判断参数是否接收完毕
return function () {
if (arguments.length < length) { // 维护一个数组知道接受完所有的参数
let combined = [fn].concat([...arguments]);
return currying(sub_currying.apply(this, combined))
} else {
return fn.apply(this, arguments) // 接受完所有的参数,执行函数
}
}
}
代码测试:
const sum = currying(add);
console.log(sum(1,2,3));
console.log(sum(1,2)(3));

这样是不是实现了面试官给的要求了,但是我们的柯里化函数还能更简单,更有便捷一些。
3.0版本(最佳版本)
其实思路和之前一样,我们只需要维护一个数组,当数组的长度与函数接收参数的个数一致时,我们就执行掉这个函数,否则就递归自身,这样不仅省去了辅助函数。使得代码更加精简,功能更加完善。
function currying(fn) {
let length = fn.length;
let args = [].slice.call(arguments,1);
return function () {
let _args = args.concat([...arguments]); // 合并参数
if(_args.length < length) { // 未接收完参数
return currying.call(this,fn,..._args);
} else { // 接受完所有参数,直接执行
return fn.apply(this,_args);
}
}
}
代码测试:
const sum = currying(add,1);
console.log(sum(2,3));
console.log(sum(2)(3));

总结
其实函数柯里化就是使我们传递参数的方式不再局限于只能一次传完,可以分步,所以柯里化的核心部分在于,当我们柯里化之后接受到的参数等于函数的参数时,我们再将函数调用,将所有参数都传进去,以上就是我对于柯里化的理解,以及实现柯里化函数的全过程。
转载自:https://juejin.cn/post/7208741162521591864