




柯里化是将多参数函数转化为单参数函数链的过程,如add(1,2,3)变为add(1)(2)(3),每次调用只传一个参数,参数满足时执行;它不改变逻辑,仅改变调用方式,区别于偏函数,需注意fn.length限制、this绑定及生产环境推荐使用lodash或ramda。
柯里化不是“把函数变复杂”,而是把多参数函数拆成一系列单参数函数,每次调用只传一个参数,直到参数够了才真正执行。
add(1, 2, 3) 到 add(1)(2)(3)
柯里化(Currying)是把接收多个参数的函数,转化为接收单一参数的函数链。它不改变函数逻辑,只改变调用方式和参数传递节奏。
典型表现:
const add = (a, b, c) => a + b + c,调用:add(1, 2, 3)
const curriedAdd = curry(add),调用:curriedAdd(1)(2)(3) 或 curriedAdd(1)(2, 3)(取决于实现是否支持多参收集聚合)注意:柯里化 ≠ 偏函数(Partial Application)。偏函数可一次传多个参数并固定部分参数,而严格柯里化每次只接受一个参数。
curry 函数(ES5+ 兼容)核心思路:利用闭包暂存已传参数,用 arguments 或剩余参数收集输入,参数数量满足时执行原函数。
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
} else {
return function(...nextArgs) {
return curried.apply(this, args.concat(nextArgs));
};
}
};
}使用示例:
const multiply = (a, b, c) => a * b * c;
const curriedMul = curry(multiply);
console.log(curriedMul(2)(3)(4)); // 24
console.log(curriedMul(2, 3)(4)); // 24(因内部用 args.length >= fn.length 判断,支持“凑够即执行”)关键点:
fn.length 返回函数声明时的形参个数(不包括 rest 参数),所以适用于普通函数apply 保持 this 上下文,否则对象方法柯里化后会丢失绑定arguments、rest 参数与 fn.length
以下情况会让基

curry 失效或行为异常:
fn.length 仍有效,但箭头函数没有 arguments 和 this,若你依赖 this 就不能直接柯里化箭头函数(a, b, ...rest) => {})→ fn.length 返回 2(忽略 ...rest),导致提前触发执行f(1)(2, 3, 4)(5))→ 基础实现只看“当前层参数总数”,不区分“本次传几个”,需改用计数器或显式 toString 触发求值await,别忘了处理 Promise 链lodash.curry 或 ramda.curry
自己写的 curry 很难覆盖所有边界(如 this 绑定、new 调用、getter/setter、Symbol.toStringTag 等)。实际项目中更推荐成熟库:
import { curry } from 'lodash':支持占位符(_),允许跳过参数,如 curry(add)(1, _, 3)(2)
import { curry } from 'ramda':默认严格单参数,且对函数式组合更友好;ramda 的 curry 还能自动识别 length 并兼容 rest 参数(通过解析 AST?不,其实是靠用户显式传入 arity)真正容易被忽略的是:柯里化后函数的 length 变成 1,这会影响依赖函数元信息的工具(比如某些类型推导、装饰器、AOP 框架),调试时看到 (...args) => {} 就知道它大概率被柯里化过了。