柯里化是将多参数函数转换为每次接收一个参数、累积后执行的函数,核心是递归收集参数并支持无参调用触发执行。

直接用函数式编程的思路:把原函数的参数逐个“吃掉”,每次只接收一个参数,直到凑够总数才执行。
核心逻辑:递归收集参数
柯里化本质是延迟求值。关键不是硬记“柯里化定义”,而是抓住两点:一是函数能接收少于原始参数个数的输入,二是返回新函数继续接收剩余参数。当累计参数数量 ≥ 原函数期望参数个数(fn.length),就立即调用。
- 用闭包保存已传入的参数列表(比如用数组
acc) - 返回的函数每次接收一个新参数,推入
acc,再判断是否满足调用条件 - 满足则
fn(...acc),否则返回自身(形成递归链)
支持可变参数的关键:不依赖固定长度
fn.length 只反映函数声明时的形参个数,对 rest 参数(...args)或动态参数不敏感。所以真正可靠的判断依据是:**用户是否显式触发执行**。常见做法是提供一个“哨兵方法”(如 toString 或 valueOf)或允许传入 undefined/null 作为结束信号;但更自然的方式是——当调用返回的柯里化函数时,若没给参数,就视为“该执行了”。
- 利用函数对象的
toString方法:在未满参时,toString返回函数体描述;满参后让它返回计算结果(隐式转换触发执行) - 或者更实用:返回的函数本身具备“可被调用”和“可被取值”双重能力——调用时传参继续累积,不传参直接执行
简洁可靠的实现(ES6+)
下面是一个兼顾可读性与健壮性的版本:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
function curry(fn) {
const curried = function(...args) {
if (args.length === 0) {
return fn.apply(this, curried.acc);
}
curried.acc.push(...args);
return curried;
};
curried.acc = [];
curried.toString = () => String(fn.apply(this, curried.acc));
curried.valueOf = () => fn.apply(this, curried.acc);
return curried;
}
用法示例:
const add = (a, b, c) => a + b + c; const curriedAdd = curry(add); console.log(curriedAdd(1)(2)(3)()); // 6 console.log(curriedAdd(1, 2)(3)()); // 6 console.log(+curriedAdd(1)(2)(3)); // 6(触发 valueOf) console.log(curriedAdd(1)(2)(3) + ''); // "6"(触发 toString)
进阶:支持 this 绑定与异步函数
上面版本默认使用调用时的 this。如果需要绑定上下文,可加一层 bind;若目标函数是异步的(返回 Promise),只需把最后的 fn.apply(...) 替换为 fn.apply(...).then(...),或统一用 await 处理。不过多数场景下,保持同步语义更清晰——柯里化本身是纯函数操作,执行时机由用户控制。
不复杂但容易忽略:真正的可变参数支持,不靠猜长度,而靠用户明确“现在该算了”。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










