告别 add(1, 2)!通过 JS 柯里化,让你的代码更加优雅

张开发
2026/6/11 5:28:01 15 分钟阅读
告别 add(1, 2)!通过 JS 柯里化,让你的代码更加优雅
在此之前的很多次面试里你可能都遇到过这样一个经典的“送命题”“请实现一个add函数使得add(1)(2)(3)的结果等于 6。”乍一看这像是面试官在故意刁难。毕竟在正常的业务开发里谁没事会把参数拆得七零八落但其实这背后藏着一个函数式编程中非常性感且实用的概念——柯里化 (Currying)。今天我们就抛开那些晦涩的数学定义用大白话和最骚的代码彻底搞懂柯里化到底是个什么鬼以及它为什么能让你的代码更优雅。 什么是柯里化从“一口闷”到“细嚼慢咽”在传统的函数调用中我们习惯“一口闷”。比如一个求和函数function add(a, b, c) { return a b c }我们要么一次性把a, b, c全传进去要么就报错。柯里化的本质就是把“一次性传参”变成“一个个传参”。如果说普通函数是$f(a, b, c)$那么柯里化后的函数就是$f(a)(b)(c)$。核心心法闭包是仓库递归是搬运工柯里化之所以能实现全靠 JavaScript 的两个老朋友闭包 (Closure)每一层函数都像一个“小仓库”记住了之前传进来的参数这些变量自由变量不会被销毁而是静静地待在那里。递归 (Recursion)只要参数还没凑够我就继续返回一个新的函数等着你传下一个参数一旦凑够了直接“召唤神龙”执行原函数。 手撸一个通用的 Curry 函数光说不练假把式。我们来看看如何把任何一个普通函数变成柯里化函数。1. 知道什么时候“够了”首先我们需要知道原函数到底需要几个参数。在 JS 里函数有一个属性length它代表了函数形参的个数。JavaScriptfunction add(a, b, c, d) { return a b c d; } console.log(add.length); // 输出 4 - 这就是我们的目标数量2. 实现核心逻辑接下来我们写一个curry辅助函数。它的逻辑非常简单粗暴参数没收齐我就一直返回函数收齐了我就执行。JavaScript/** * 柯里化通用实现 * param {Function} fn - 需要被柯里化的原函数 */ function curry(fn) { // 这里的 ...args 是闭包这层仓库里已经存好的参数 return function curried(...args) { // 【核心判断】当前收集的参数数量 原函数需要的参数数量 if (args.length fn.length) { // 退出条件参数够了直接执行原函数 return fn(...args); } else { // 递归继续参数不够返回一个新的函数继续收参数 return (...rest) { // 将之前存的 args 和新传进来的 rest 合并递归调用 curried return curried(...args, ...rest); }; } } }3. 见证奇迹的时刻现在我们用这个curry函数来包装一下我们的addJavaScriptconst curriedAdd curry(add); // 玩法 1标准柯里化一次传一个 console.log(curriedAdd(1)(2)(3)(4)); // 10 // 玩法 2不严谨柯里化一次传多个更灵活 console.log(curriedAdd(1, 2)(3)(4)); // 10 console.log(curriedAdd(1, 2, 3, 4)); // 10你看无论你怎么传只要总数凑够了 4 个它就会给你吐出结果。这就是闭包在背后默默负重前行的结果。 为什么我要用它实战场景你可能会问“这就这就除了面试装X这有啥用”柯里化最大的价值在于参数复用偏函数应用与 延迟执行。场景打造优雅的日志系统假设你有一个通用的日志打印函数JavaScript// 通用日志函数 const log (type, message) { console.log([${type}]: ${message}); }在实际业务中你要打印很多ERROR类型的日志。如果不柯里化你得这么写JavaScriptlog(ERROR, 接口挂了); log(ERROR, 数据不对); log(ERROR, 服务器着火了);太 啰 嗦 了ERROR这个参数我们重复写了三遍。利用柯里化或者在这里更准确说是偏函数应用的思想我们可以“固定”住第一个参数JavaScript// 这里我们用箭头函数简写一个针对 log 的柯里化版本 const curriedLog type message { console.log([${type}]: ${message}); } // 批量生产专用函数 const errorLog curriedLog(ERROR); // 固定住了 ERROR const infoLog curriedLog(INFO); // 固定住了 INFO // ✅ 现在的调用语义更清晰代码更简洁 errorLog(接口挂了); // [ERROR]: 接口挂了 infoLog(页面加载完成); // [INFO]: 页面加载完成这一波操作下来代码的可读性errorLog一眼就知道是干嘛的和复用性不用重复传type都得到了极大的提升。 总结一下柯里化 (Currying)是一种将多参数函数转换为一系列单参数函数的技术。实现原理利用闭包保存历史参数利用递归收集参数利用fn.length判断退出时机。应用场景当你需要频繁调用一个函数且其中某些参数是固定的时候柯里化能帮你通过“预置参数”来减少重复代码提升代码的语义化。下次再看到add(1)(2)(3)别再觉得它是花拳绣腿了。它是 JavaScript 函数式编程中一把精致的手术刀用得好你的代码就能像诗一样优雅。✨

更多文章