柯里化是将多参函数拆为单参函数链,不改逻辑只变调用方式;核心用闭包缓存参数,依fn.length判断执行时机,需正确处理this和剩余参数。
柯里化不是“把函数变复杂”,而是把一个接收多个参数的函数,拆成一系列只接收一个参数的函数。它不改变原函数逻辑,只改变调用方式。
核心是利用闭包保存已传入的参数,直到参数总数满足原函数要求才执行。常见错误是没处理 length 动态变化或箭头函数没有 arguments。
fn.length 获取形参个数,但注意:它只反映函数声明时的参数数量,不包含 rest 参数(...args)arguments —— 箭头函数没有该对象,应统一用剩余参数 ...args
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
}
return function (...moreArgs) {
return curried.apply(this, args.concat(moreArgs));
};
};
}
因为 curry 需要支持 this 上下文绑定,而 Array.prototype.slice.call 只处理类数组,不保留调用时的 this。更严重的是,现代代码中大量使用箭头函数或严格模式,arguments 不可靠。
fn.apply(this, args) 是必须的,确保原函数内部的 this 正确指向调用者[].slice.call(arguments),改用 Array.from(arguments) 或直接用 ...args
this 的对象方法,漏掉 this 绑定会导致 undefined 报错柯里化真正有用的地方,是提前固化部分配置,让后续调用更简洁。比如日志加前缀、API 基地址、按钮点击行为复用。
const logError = curry(console.error).bind(null, '[ERROR]') —— 后续只需 logError('user not found')
const getUser = curry(fetch).bind(null, 'https://api.example.com/')('users/'),但注意:fetch 第二个参数是配置对象,需按实际参数结构设计 curry 层级button.addEventListener('click', curry(handleClick)(userId)),比 () => handleClick(userId) 更利于内存回收(前提是 handleClick 本身无闭包泄漏)柯里化容易被过度设计 —— 如果函数只有两三个参数且调用场景固定,硬套 curry 反而增加理解成本。重点看是否真有“参数分批注入”的需求,而不是为函数式而函数式。