柯里化能直接提升参数复用性并保证函数纯净度;它通过冻结高频配置实现复用,生成的中间函数均为纯函数,具备无副作用、可缓存、易测试特性,但需注意参数顺序、函数声明方式及上下文保留等实现细节。

柯里化能直接提升参数复用性,同时天然支持函数纯净度——它不修改外部状态、不依赖可变变量、每次调用只依赖输入参数,返回确定结果。
参数复用:固定高频配置,减少重复传参
当某类参数在多个调用中保持不变(如日志级别、API前缀、正则规则),柯里化可将其“冻结”为新函数,后续调用只需传动态部分。
- 日志封装:const errorLog = curry(console.log)('ERROR:');之后
errorLog('user timeout')自动补全前缀,无需每次写完整字符串 - 表单验证:const checkPhone = curry(/^(1[3-9])\d{9}$/.test);后续
checkPhone('13812345678')直接返回布尔值,正则逻辑只定义一次 - 请求预设:const apiGet = curry(fetch)('https://api.example.com');再配合 token 固定,生成专用请求函数,避免重复拼 URL
函数纯净度:无副作用、可缓存、易测试
柯里化生成的每个中间函数都是纯函数:相同输入必得相同输出,不读写外部变量,也不改变 this 或全局状态。
- 因为所有已传参数都通过闭包暂存在独立作用域中,不会被其他调用干扰。例如
add5 = curry(add)(5)和add10 = curry(add)(10)完全隔离 - 纯函数天然支持记忆化(memoization):对
curry(Math.pow)(2)的结果缓存后,[1,2,3].map(...)中多次调用 2 的平方可直接命中缓存 - 单元测试更简单:只需验证
checkEmail('test@domain.com')是否返回 true,不用模拟环境或 mock console
关键实现细节:确保复用可靠、纯净不破防
手写 curry 时,三点必须守住:
- 用 fn.length 判断形参个数,但注意箭头函数 length 为 0,建议优先使用普通函数声明,或显式传入期望参数数
-
每次返回新函数必须是具名函数表达式(如
function curried() {...}),不能用箭头函数,否则递归调用会失败 -
用 apply(this, args) 保留原始上下文,若目标函数是对象方法(如
obj.method),丢失 this 会导致行为异常
不是所有场景都适合柯里化
参数复用价值高,但需匹配使用习惯:
- 参数顺序很重要:把最稳定、最常复用的参数放在最前面,比如
curry(fetch)(baseUrl)(options)比curry(fetch)(options)(baseUrl)更实用 - rest 参数(...args)或动态参数多的函数,柯里化后难以准确判断何时执行,建议改用工厂函数(
x => y => x + y)或 Lodash 的_.partial - 过度柯里化会增加认知负担,比如五层嵌套
f(a)(b)(c)(d)(e)不如明确拆成配置对象或两步调用










