函数柯里化实现
描述
柯里化(Currying)是将接受多个参数的函数转换为接受一个参数的一系列函数的技术。
核心原理
- 收集参数
- 参数不足时返回新函数继续收集
- 参数足够时执行原函数
实现代码
基础版(固定参数数量)
js
function curry(fn) {
const arity = fn.length;
return function curried(...args) {
if (args.length >= arity) {
return fn.apply(this, args);
}
return function (...args2) {
return curried.apply(this, [...args, ...args2]);
};
};
}完整版(支持不定参数)
js
function curry(fn, ...args) {
return function (...args2) {
const allArgs = [...args, ...args2];
if (allArgs.length >= fn.length) {
return fn.apply(this, allArgs);
}
return curry(fn, ...allArgs);
};
}简化版(参数够了就调用)
js
function curry(fn) {
return function (...args) {
if (args.length >= fn.length) {
return fn(...args);
}
return (...args2) => fn(...args, ...args2);
};
}带占位符的版本
js
function curry(fn) {
const allArgs = [];
function curried(...args) {
allArgs.push(...args);
if (allArgs.length >= fn.length) {
const result = fn(...allArgs);
allArgs.length = 0; // 重置
return result;
}
return curried;
}
curried.reset = () => {
allArgs.length = 0;
};
return curried;
}使用示例
js
// 普通函数
function add(a, b, c) {
return a + b + c;
}
const curriedAdd = curry(add);
// 逐步传参
console.log(curriedAdd(1)(2)(3)); // 6
console.log(curriedAdd(1, 2)(3)); // 6
console.log(curriedAdd(1)(2, 3)); // 6
console.log(curriedAdd(1, 2, 3)); // 6
// 实际应用:预设配置
const fetchWithAuth = curry((url, headers, body) => {
return fetch(url, { ...headers, ...body });
});
const fetchWithToken = fetchWithAuth("/api/user", { Authorization: "Bearer token" });
const post = fetchWithToken({ method: "POST" });
const get = fetchWithToken({ method: "GET" });
// 网络请求
const request = curry((method, url, data) => {
console.log(`${method} ${url}`, data);
});
const getRequest = request("GET");
const postRequest = request("POST");
getRequest("/users"); // GET /users undefined
postRequest("/users", { name: "张三" }); // POST /users { name: '张三' }反柯里化
描述
反柯里化(Uncurrying)是将接受单一参数的函数转换为接受多个参数的函数。
实现代码
js
Function.prototype.uncurry = function () {
const fn = this;
return function (...args) {
return fn.apply(args.shift(), args);
};
};
// 或者
Function.prototype.uncurry = function () {
const fn = this;
return Function.apply.bind(fn);
};使用示例
js
const push = Array.prototype.push.uncurry();
const arr = [1, 2];
push(arr, 3, 4);
console.log(arr); // [1, 2, 3, 4]
// 类似 Function.call
const call = Function.prototype.call.uncurry();
call(console.log, null, "hello"); // 'hello'柯里化 vs 反柯里化对比
| 特性 | 柯里化 | 反柯里化 |
|---|---|---|
| 方向 | 多参转单参 | 单参转多参 |
| 目的 | 预设参数 | 扩展方法适用范围 |
| 应用 | 函数式编程 | OOP 向函数式过渡 |