柯里化是将多参函数转换为单参函数链的过程,每次只接收一个参数并返回新函数,直至参数收齐才执行原逻辑;核心在于参数分层与部分应用,而非语法炫技。

柯里化是什么:不是“把函数变复杂”,而是“把多参函数拆成单参链”
柯里化(Currying)不是给函数加装饰,也不是为了炫技。它本质是把一个接受多个参数的函数,转换为一系列每次只接收一个参数的函数,且每次返回一个新的函数,直到所有参数收齐才真正执行原逻辑。add(1, 2, 3) 经柯里化后可写成 add(1)(2)(3) 或 add(1)(2)(3),中间任意一步都可缓存、复用、组合。
手写 curry 函数:用闭包和 arguments / rest 收集参数
最简实现依赖两个核心:一是记住原始函数和已传参数,二是判断参数是否够数。现代写法优先用 ...args,但要注意 length 属性只反映函数声明的形参个数,不包含 rest 参数。
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
} else {
return function(...moreArgs) {
return curried.apply(this, args.concat(moreArgs));
};
}
};
}
-
fn.length是原始函数期望的参数个数,比如function(a, b, c) {}的length是 3 - 每次调用
curried都会累积参数,不够就返回新函数;够了就直接执行fn - 没处理
this绑定时可能出错,实际项目中建议用fn.bind(this, ...args)替代apply以保留上下文
用 lodash.curry 时容易忽略的三个细节
直接引入 lodash.curry 看似省事,但默认行为和直觉有偏差:
- 它不强制“一次一个”,支持
curried(1, 2)(3)或curried(1)(2, 3)—— 只要累计够数就执行 - 不自动识别箭头函数的
length(箭头函数无arguments,length恒为 0),必须显式传入占位符或用_.curry(fn, arity)指定参数个数 - 返回的函数带
placeholder属性,允许写curried(_, 2, _)(1)(3),但多数人根本不用,反而造成调试困惑
柯里化真正在用的场景,不是“为了柯里化而柯里化”
它最有价值的地方,在于提前固化部分参数,生成特化函数,而不是追求链式调用形式:
立即学习“Java免费学习笔记(深入)”;
- 配置复用:
const ajaxGet = curry(fetch)(undefined, { method: 'GET' }),后续只需传 URL - 事件处理器预置:
const handleClick = curry(handleAction)('delete'),绑定到 DOM 时无需内联箭头函数 - 与函数式工具链配合:
compose(map(curry(Math.pow)(2)), filter(isEven)),避免写x => Math.pow(2, x) - 注意:高频调用场景慎用,每次柯里化都新建闭包,有内存和性能成本;简单二元操作如
add、multiply更适合直接写箭头函数
柯里化的关键不在语法糖,而在“参数分层”意识——哪些参数稳定、哪些易变,决定了你该在哪儿切一刀。写多了就会发现,真正难的不是怎么实现 curry,而是判断某个函数值不值得被柯里化。










