告别重复传参!用柯里化提升代码优雅度

柯里化:让函数"慢慢来",一次只吃一口

在编程世界里,我们常常会遇到这样一种场景:一个函数需要多个参数才能完成任务。但有时候,这些参数并不会一下子全部准备好------可能今天知道第一个,明天拿到第二个,后天才凑齐全部。

这时候,柯里化(Currying) 就派上用场了。它就像一位耐心的厨师,不急着把整道菜做完,而是先记住你已经给的食材,等你把剩下的材料陆续送来,再一锅炒好。


从最简单的加法说起

假设我们有一个普通的加法函数:

js 复制代码
function add(a, b) {
  return a + b;
}
console.log(add(1, 2)); // 输出 3

这很直接:两个数一起传进去,立刻出结果。但如果我只能先给你 a,过一会儿再告诉你 b 呢?普通函数就无能为力了。

于是我们可以手动"柯里化"一下:

js 复制代码
function add(a) {
  return function(b) {
    return a + b;
  };
}
console.log(add(1)(2)); // 输出 3

你看,现在 add(1) 返回的是一个新函数,这个函数"记得"了 a = 1,等你再调用它传入 b,就能算出结果。这背后靠的是 闭包------内部函数可以"记住"外部函数的变量,即使外部函数已经执行完了。

这种写法虽然可行,但只适用于固定两个参数的情况。如果函数有三个、四个甚至更多参数,手动嵌套写起来会非常繁琐,而且难以复用


自动柯里化:通用解决方案

手动为每个函数写柯里化版本太麻烦了。有没有办法写一个"万能工具",自动把任意多参函数变成可逐步传参的形式?

当然有!来看这个通用的 curry 函数:

js 复制代码
function add(a, b, c, d) {
  return a + b + c + d;
}

function curry(fn) {
  return function curried(...args) {
    if (args.length >= fn.length) {
      return fn(...args); // 参数够了,直接执行
    }
    return (...rest) => curried(...args, ...rest); // 不够?继续收
  };
}

const curriedAdd = curry(add);
console.log(curriedAdd(1)(2)(3)(4)); // 10
console.log(curriedAdd(1, 2)(3, 4)); // 10,也可以一次传多个

它是怎么工作的?

  • fn.length 是 JavaScript 中函数的一个属性,表示该函数声明时定义的参数个数(不包括剩余参数)。
  • 每次调用 curried,都会收集当前传入的参数(通过 ...args)。
  • 如果当前参数数量 ≥ 原函数所需参数数量,就立即执行 fn(...args)
  • 否则,返回一个新函数,这个新函数会把已有的 args 和后续传入的 rest 合并,再次调用 curried ------ 这就是递归的思想。

只要收集到足够数量的参数,就立刻执行;否则,返回一个新函数继续等待。

🔍 注意 :这个实现利用了 闭包 + 递归 的思想。每次调用都把已有的参数"存起来",直到攒够为止。而闭包保证了这些中间参数不会丢失。


实战:日志函数的柯里化妙用

柯里化不只是炫技,它在实际开发中非常有用。比如处理日志:

js 复制代码
const log = type => message => {
  console.log(`${type}: ${message}`);
};

const errorLog = log('ERROR');
const infoLog = log('info');

errorLog('接口异常');        // 输出: ERROR: 接口异常
infoLog('页面加载完成');     // 输出: info: 页面加载完成

这里,log 是一个柯里化函数。我们先固定日志类型(如 'ERROR'),得到一个专门打错误日志的函数 errorLog。以后只要传消息内容就行,不用每次都写类型。

优势在哪里?

  1. 减少重复代码 :不需要每次写 log('error', 'xxx')
  2. 提高可读性errorLog('xxx')log('error', 'xxx') 更直观。
  3. 便于组合与复用:可以轻松创建不同级别的日志器,并在多个模块中共享。

总结:柯里化的三大核心

  1. 闭包:保存已传入的参数,不会被垃圾回收。
  2. 递归/链式调用:每次返回新函数,继续接收剩余参数。
  3. 退出条件 :当参数数量达到原函数要求(fn.length),就执行并返回结果。

柯里化不是必须用的技术,但它能让你的函数更灵活、更具组合性。就像乐高积木------你可以先拼好一部分,等需要时再接上其他模块,最终搭出完整作品。

下次当你发现某个函数总是在不同地方传相同的前几个参数时,不妨试试柯里化------让函数学会"等一等",说不定代码会变得更优雅!

相关推荐
崔庆才丨静觅6 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60617 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了7 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅7 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅8 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅8 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment8 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅8 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊8 小时前
jwt介绍
前端
爱敲代码的小鱼9 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax