柯里化是将多参函数转换为一系列单参函数链式调用的机制,核心是每次只接收一个参数、用闭包累积已传参数,待参数总数达原函数length时执行;需注意箭头函数length为0、rest参数影响length判断等边界。

把普通函数变成 f(a)(b)(c) 这种形式,关键不是“加个闭包”就完事,而是让每次调用都返回一个新函数,并用闭包记住前面传过的参数,直到参数凑齐才真正执行原逻辑。
明确柯里化的核心契约
它不是简单地套一层函数,而是有明确规则:
- 每次只接收一个参数,不能跳步、不能合并传入多个
- 参数不足时必须返回函数,哪怕只传了第一个参数也要能继续链式调用
- 最终执行时机由参数总数决定——通常靠
fn.length判断原函数期望几个参数 - 所有中间函数共享同一份已传参数,靠闭包维持状态,不是每次新建空数组
手动实现一个可靠的基础版本
不依赖工具库,几行代码就能写出可复用的柯里化函数:
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn(...args);
}
return (...nextArgs) => curried(...args, ...nextArgs);
};
}
说明:
-
...args收集当前轮次传入的参数(每次只传一个,但写法上兼容多传) - 用
fn.length获取原函数形参个数,作为“收尾信号” - 返回的箭头函数通过闭包访问外层
args,拼接新参数后递归调用curried - 箭头函数自动绑定词法作用域,避免
this问题
注意常见误区和边界情况
实际用时容易踩坑,这些点要留心:
-
不要混淆偏函数:像
makeAdder(2)返回y => 2 + y是偏应用,它固定了部分参数但不承诺单参数链式调用 -
rest 参数会影响 fn.length:如果原函数是
(a, b, ...rest),fn.length只返回 2,需额外处理或改用显式参数计数 -
箭头函数没有 .length:传入箭头函数做
fn时,fn.length为 0,建议只对具名/声明函数柯里化,或加 fallback 提示 -
多次调用同一柯里化函数互不影响:每个
curry(sum)调用都生成独立闭包,参数状态不共享
典型使用场景帮你理解价值
柯里化不是炫技,解决的是真实开发痛点:
-
参数复用:比如校验函数
check(reg, str)柯里化后,const hasEmail = curry(check)(/^\S+@\S+\.\S+$/),后续直接hasEmail('test@x.com') -
配置提前注入:API 请求函数
request(method, url, data)→const post = curry(request)('POST'),再post('/login', {u:1}) - 适配函数组合:在 pipe 或 compose 链中,所有函数必须是单参数,柯里化让多参函数自然融入











