函数柯里化详解
一、柯里化基本概念
柯里化(Currying) 是一种函数转换技术,它将一个接收多个参数的函数转换为一系列接收单个参数的函数,并返回接收余下参数的新函数。
基本数学原理
普通函数:f(a, b, c)
柯里化后:f(a)(b)(c)
二、实现原理与核心代码
我们正常情况下写sum函数是
const sum = function(a,b) {
return a + b;
}
// 调用
sum(1,2)
柯里化后
const sum = function(a) {
return function(b) {
return a + b;
}
}
// 调用
sum(1)(2)
闭包相当于 ⬇️
function(b) {
return a + b;
}(2)
解决N个参数的问题,使用递归函数。
为了解决将所有的函数变成柯里化,所以我们的入参要加上fn
function currying(fn, length) {
// 第一次调用获取函数 fn 参数的长度,后续调用获取 fn 剩余参数的长度
length = length || fn.length;
// currying 包裹之后返回一个新函数,接收参数为 ...args
return function (...args) {
// 新函数接收的参数长度是否大于等于 fn 剩余参数需要接收的长度
return args.length >= length
? fn.apply(this, args) // 满足要求,执行 fn 函数,传入新函数的参数
: currying(fn.bind(this, ...args), length - args.length)
// 不满足要求,递归 currying 函数,新的 fn 为 bind 返回的新函数
//(bind 绑定了 ...args 参数,未执行),新的 length 为 fn 剩余参数的长度
}
}
const sum = function(a,b,c){
return a + b + c;
}
const currySum = currying(sum);
console.log(currySum(1,2,3));
console.log(currySum(1)(2)(3));
console.log(currySum(1,2)(3));
// 输出都是 6
二、实际应用场景
1. 参数复用
javascript
javascript
下载
复制
// 普通函数
function createURL(protocol, domain, path) {
return `${protocol}://${domain}/${path}`;
}
// 柯里化后
const curriedURL = curry(createURL);
const httpsURL = curriedURL('https'); // 固定协议
const githubAPI = httpsURL('api.github.com'); // 固定域名
console.log(githubAPI('users/octocat')); // https://api.github.com/users/octocat
2. 延迟计算
javascript
javascript
下载
复制
// 日志工具
const curriedLog = curry((level, timestamp, message) => {
console[level](`[${timestamp}] ${message}`);
});
const logWithTime = curriedLog('log')(new Date().toISOString());
logWithTime('用户登录成功'); // [2024-01-15T10:30:00Z] 用户登录成功
logWithTime('数据保存成功'); // 复用时间戳
3. 函数组合
javascript
javascript
下载
复制
// 工具函数
const map = curry((fn, array) => array.map(fn));
const filter = curry((fn, array) => array.filter(fn));
const reduce = curry((fn, initial, array) => array.reduce(fn, initial));
// 组合使用
const numbers = [1, 2, 3, 4, 5];
const add = curry((a, b) => a + b);
// 计算大于2的数的总和
const result = pipe(
filter(n => n > 2),
map(n => n * 2),
reduce(add, 0)
)(numbers);
console.log(result); // 24
4. 配置预设
javascript
javascript
下载
复制
// API请求配置
const apiRequest = curry((method, endpoint, data, headers) => {
return fetch(endpoint, { method, body: JSON.stringify(data), headers });
});
// 预设配置
const post = apiRequest('POST');
const postJSON = post(null, { 'Content-Type': 'application/json' });
// 使用预设
postJSON('/api/users', { name: '张三' })
.then(res => res.json());
总结
柯里化的核心价值:
- 参数复用:固定某些参数,创建更具体的函数
- 延迟执行:参数不完整时不执行,返回新函数
- 函数组合:便于创建管道式函数调用
- 提高可读性:将多参数函数转换为可链式调用的单参数函数
适用场景:
- 需要固定部分参数的函数调用
- 函数式编程中的函数组合
- 创建可配置的工具函数
- 提高代码的复用性和可读性
注意事项:
- 不适合需要动态
this的函数 - 注意默认参数对
fn.length的影响 - 在性能敏感场景考虑缓存优化