JavaScript篇:柯里化函数:像‘吃薯片’一样拆分参数,你会上瘾! 🍟

大家好,我是江城开朗的豌豆,一名拥有6年以上前端开发经验的工程师。我精通HTML、CSS、JavaScript等基础前端技术,并深入掌握Vue、React、Uniapp、Flutter等主流框架,能够高效解决各类前端开发问题。在我的技术栈中,除了常见的前端开发技术,我还擅长3D开发,熟练使用Three.js进行3D图形绘制,并在虚拟现实与数字孪生技术上积累了丰富的经验,特别是在虚幻引擎开发方面,有着深入的理解和实践。

我一直认为技术的不断探索和实践是进步的源泉,近年来,我深入研究大数据算法的应用与发展,尤其在数据可视化和交互体验方面,取得了显著的成果。我也注重与团队的合作,能够有效地推动项目的进展和优化开发流程。现在,我担任全栈工程师,拥有CSDN博客专家认证及阿里云专家博主称号,希望通过分享我的技术心得与经验,帮助更多人提升自己的技术水平,成为更优秀的开发者。

技术qq交流群:906392632

大家好,我是小杨,做了6年前端。今天要聊一个听起来高大上、用起来真香的技术------柯里化函数 。第一次听到这个词时,我以为是某种"咖喱味"的代码写法(笑),后来才发现它能让复杂函数变得像吃薯片一样------一片一片拆着吃,越吃越上头


一、什么是柯里化?先看个生活例子

想象你去奶茶店点单:

  1. 普通点法:一次性说完"我要大杯冰乌龙奶茶加珍珠少糖"

  2. 柯里化点法

    • 第一步:"我要大杯"(确定杯型)
    • 第二步:"加冰"(确定温度)
    • 第三步:"乌龙奶茶"(确定品类)
    • ... 最后得到完整订单

柯里化就是把多参数函数拆成单参数函数链

javascript 复制代码
// 普通函数
function makeTea(size, ice, type, sugar) {
  return `${size}杯${ice}${type}${sugar}糖`;
}

// 柯里化版本
function curryMakeTea(size) {
  return function(ice) {
    return function(type) {
      return function(sugar) {
        return `${size}杯${ice}${type}${sugar}糖`;
      };
    };
  };
}

// 使用对比
makeTea('大杯', '冰', '乌龙奶茶', '少'); // 一次性传完
curryMakeTea('大杯')('冰')('乌龙奶茶')('少'); // 分步传参

二、我为什么爱上柯里化?3个真实场景

场景1:参数复用(避免重复传参)

处理API请求时,经常要带固定token:

javascript 复制代码
// 普通写法:每次都要传token
function fetchApi(token, url, params) { /*...*/ }

// 柯里化后
function curryFetchApi(token) {
  return function(url) {
    return function(params) {
      return fetch(url, { ...params, headers: { Authorization: token } });
    };
  };
}

// 生成带token的专用函数
const fetchWithToken = curryFetchApi('my_token123');
const getUser = fetchWithToken('/api/user');
const getOrder = fetchWithToken('/api/order');

// 使用
getUser({ id: 1 }); // 自动携带token
getOrder({ id: 2 });

场景2:延迟执行(动态生成函数)

实现一个可定制的logger:

javascript 复制代码
function createLogger(prefix) {
  return function(message) {
    console.log(`[${prefix}] ${message}`);
  };
}

const myLogger = createLogger('小杨');
myLogger('函数柯里化真好用!'); // [小杨] 函数柯里化真好用!

场景3:React中的高阶组件(HOC)

(虽然现在流行hooks,但老项目里很常见)

javascript 复制代码
const withLoading = (WrappedComponent) => {
  return function(props) {
    return props.isLoading 
      ? <div>加载中...</div>
      : <WrappedComponent {...props} />;
  };
};

// 使用
const UserListWithLoading = withLoading(UserList);

三、手写一个通用柯里化工具函数

很多库(如lodash)自带_.curry,但我们自己实现也不难:

javascript 复制代码
function curry(fn) {
  return function curried(...args) {
    // 参数足够时直接执行
    if (args.length >= fn.length) {
      return fn.apply(this, args);
    } 
    // 不够时返回新函数继续收集
    else {
      return function(...args2) {
        return curried.apply(this, args.concat(args2));
      };
    }
  };
}

// 使用示例
const add = (a, b, c) => a + b + c;
const curriedAdd = curry(add);
console.log(curriedAdd(1)(2)(3)); // 6
console.log(curriedAdd(1, 2)(3)); // 6

我的踩坑记录

第一次写忘了处理fn.length(函数形参数量),导致无限循环,大家一定要注意!


四、柯里化 vs 部分应用(别搞混了!)

经常被混淆的两个概念:

特性 柯里化 (Currying) 部分应用 (Partial Application)
参数传递 每次只传一个参数 可以一次传多个参数
结果形态 嵌套的单参数函数 直接返回部分执行的函数
典型实现 a => b => c => a+b+c bind(this, 1, 2)

简单说

  • 柯里化是 "全有或全无" (必须拆到最小单元)
  • 部分应用是 "随意搭配" (想传几个传几个)

五、什么时候不要用柯里化?

  1. 性能敏感场景:多层嵌套调用会有额外开销
  2. 代码可读性差时 :过度柯里化会让调用链太长(比如a()()()()()
  3. 团队不熟悉时:如果组员都看不懂,不如写普通函数

六、总结:柯里化的甜点时刻 🍰

适合场景

  • 参数有明显层次关系(如配置→数据)
  • 需要复用部分参数
  • 编写高阶函数或组合函数

不适合场景

  • 参数之间强耦合
  • 需要快速迭代的临时函数

最后一句心里话:6年前我第一次看柯里化代码时觉得"这特么什么鬼",现在写工具函数却总忍不住柯里化一下------真香!你有类似的真香经历吗?评论区见!

相关推荐
PAK向日葵5 分钟前
【算法导论】PDD 0817笔试题题解
算法·面试
加班是不可能的,除非双倍日工资2 小时前
css预编译器实现星空背景图
前端·css·vue3
wyiyiyi3 小时前
【Web后端】Django、flask及其场景——以构建系统原型为例
前端·数据库·后端·python·django·flask
gnip3 小时前
vite和webpack打包结构控制
前端·javascript
excel4 小时前
在二维 Canvas 中模拟三角形绕 X、Y 轴旋转
前端
阿华的代码王国4 小时前
【Android】RecyclerView复用CheckBox的异常状态
android·xml·java·前端·后端
一条上岸小咸鱼4 小时前
Kotlin 基本数据类型(三):Booleans、Characters
android·前端·kotlin
Jimmy4 小时前
AI 代理是什么,其有助于我们实现更智能编程
前端·后端·ai编程
ZXT4 小时前
promise & async await总结
前端
Jerry说前后端4 小时前
RecyclerView 性能优化:从原理到实践的深度优化方案
android·前端·性能优化