柯里化通过分离“变”与“不变”实现通用逻辑复用:固定公共参数(如baseurl、模块名、校验规则)生成新函数,暴露灵活业务入口,适用于请求封装、表单验证、日志埋点等场景,但需避免过度使用。

柯里化函数复用通用业务逻辑,核心是把“变”和“不变”分离:固定部分参数形成新函数,让后续调用只需传入业务差异点。它不是为炫技,而是让校验、请求、日志、权限等通用流程可配置、可组合、不重复写。
用柯里化封装可配置的请求函数
比如统一处理 loading、错误提示、token 注入,但不同接口路径、方法、数据结构各不相同。柯里化能提前固化公共行为,暴露灵活入口:
const createRequest = (baseUrl, defaultOptions = {}) =>
(path, options = {}) => {
const config = { ...defaultOptions, ...options };
return fetch(`${baseUrl}${path}`, {
headers: {
'Authorization': `Bearer ${config.token || localStorage.token}`,
...config.headers
},
...config
}).then(res => {
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
});
};
// 复用:生成不同域下的请求函数
const apiV1 = createRequest('https://api.example.com/v1');
const adminApi = createRequest('https://admin.example.com', {
method: 'POST',
headers: { 'Content-Type': 'application/json' }
});
// 各业务处直接调用,不用重复写 base URL 或默认头
apiV1('/users').then(...);
adminApi('/roles', { body: JSON.stringify({ name: 'editor' }) });
柯里化 + 高阶函数组合通用校验逻辑
表单验证常有「必填」「长度限制」「正则匹配」等通用规则。柯里化后可先定义规则工厂,再按需组装:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
// 规则生成器(柯里化)
const required = (msg = '此项必填') => (value) =>
value != null && value !== '' ? undefined : msg;
const maxLength = (max, msg = `最多${max}个字符`) => (value) =>
typeof value === 'string' && value.length (value) =>
!value || reg.test(value) ? undefined : msg;
// 组合复用
const validateUsername = [required(), maxLength(20), pattern(/^[a-z0-9_]+$/i)];
const validateEmail = [required(), pattern(/^.+@.+\..+$/)];
// 通用校验执行器
const validate = (rules) => (value) => rules.reduce((err, rule) => err || rule(value), undefined);
// 业务中直接使用
const usernameErr = validate(validateUsername)('my_user_123'); // undefined
const emailErr = validate(validateEmail)('invalid-email'); // '格式不正确'
用柯里化抽象日志与埋点行为
打日志或上报埋点时,环境、模块名、版本号往往固定,而事件名、参数动态变化。柯里化可预先绑定上下文:
const createLogger = (env, module, version) => (event, data = {}) => {
console.log(`[${env}][${module}@${version}] ${event}`, {
timestamp: Date.now(),
...data
});
// 实际可替换为上报 SDK 调用
};
// 生成各模块专属 logger
const userLogger = createLogger('prod', 'user', '2.1.0');
const paymentLogger = createLogger('staging', 'payment', '1.8.3');
// 业务代码干净简洁
userLogger('login_success', { uid: 12345 });
paymentLogger('pay_failed', { orderId: 'PAY-789', reason: 'insufficient_balance' });
注意边界:柯里化不是万能胶
过度柯里化会让调用链变长、调试困难,尤其当参数顺序不合理或中间态函数语义模糊时。建议遵循:
- 只对真正稳定的参数做前置固化(如 API 基地址、模块标识、默认配置)
- 保持参数顺序符合直觉:通用在前,业务在后(如 createX(a, b)(c, d) 比 createX(a)(b, c, d) 更易读)
- 配合 TypeScript 类型推导,避免丢失参数类型信息
- 简单场景优先用对象配置(如 fn({ baseUrl, timeout })),柯里化更适合需要多次复用同一配置的场景
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










