什么是柯里化_JavaScript中如何转换函数

柯里化是将多参函数拆为单参函数链,不改逻辑只变调用方式;核心用闭包缓存参数,依fn.length判断执行时机,需正确处理this和剩余参数。

柯里化不是“把函数变复杂”,而是把一个接收多个参数的函数,拆成一系列只接收一个参数的函数。它不改变原函数逻辑,只改变调用方式。

curry 函数怎么写(基础版)

核心是利用闭包保存已传入的参数,直到参数

总数满足原函数要求才执行。常见错误是没处理 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));
    };
  };
}

为什么 Array.prototype.slice.call 不能直接用在 curry 里

因为 curry 需要支持 this 上下文绑定,而 Array.prototype.slice.call 只处理类数组,不保留调用时的 this。更严重的是,现代代码中大量使用箭头函数或严格模式,arguments 不可靠。

  • fn.apply(this, args) 是必须的,确保原函数内部的 this 正确指向调用者
  • 不要用 [].slice.call(arguments),改用 Array.from(arguments) 或直接用 ...args
  • 如果原函数是 class 方法或依赖 this 的对象方法,漏掉 this 绑定会导致 undefined 报错

实际用例:log、fetch、事件处理器

柯里化真正有用的地方,是提前固化部分配置,让后续调用更简洁。比如日志加前缀、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 反而增加理解成本。重点看是否真有“参数分批注入”的需求,而不是为函数式而函数式。