柯里化
🌰 1. 柯里化意义
柯里化(Currying)本质就是把一个多参数函数拆成若干个一参函数链式调用,即把 fn(a, b, c) 变成 fn(a)(b)(c) 的技术。
Currying 指将一个接收多个参数的函数,转换成一系列接收单一参数的函数,并且返回一个新的函数,逐步接收并收集参数,直到参数足够后再执行原函数。
🌟 2. 柯里化作用
柯里化不是为了装逼,它的核心价值主要有三:
① 复用参数(函数预置参数)
const add = (a, b) => a + b;
const add5 = curry(add)(5);
add5(10) // 15
② 提高函数组合能力
const match = curry((reg, str) => reg.test(str));
const isPhone = match(/^1\d{10}$/);
isPhone("13812345678"); // true
③ 延迟执行(参数收集满了再执行)
例如防抖节流里参数不固定时很好用
🔧 3. 实现柯里化
👉 固定参数长度
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
}
return (...rest) => curried(...args, ...rest);
};
}
测试一下:
const sum = (a, b, c) => a + b + c;
curry(sum)(1)(2)(3); // 6
curry(sum)(1, 2)(3); // 6
curry(sum)(1)(2, 3); // 6
🧠 不固定参数长度
比如:
add(1)(2)(3)(4).valueOf() === 10
或:
add(1)(2)(3)() === 6
实现思路:
- 不固定参数长度
- 不停收集
- 重写
toString/valueOf/[Symbol.toPrimitive]
示例:
function add(...args) {
let total = args.reduce((s, v) => s + v, 0);
function inner(...rest) {
if (rest.length === 0) return total;
total += rest.reduce((s, v) => s + v, 0);
return inner;
}
inner.toString = () => total;
inner.valueOf = () => total;
return inner;
}
add(1)(2)(3)() // 6
+add(1)(2)(3)(4) // 10
🎯 柯里化应用
① 业务逻辑复用
const validate = curry((rule, value) => rule.test(value));
const isEmail = validate(/@/);
const isPhone = validate(/^1\d{10}$/);
② 事件绑定(偏应用)
const handleChange = curry((field, e) => {
form[field] = e.target.value;
});
<input onChange={handleChange("username")} />
③ Redux / Ramda 里大量使用
const map = curry((fn, arr) => arr.map(fn));
偏函数
偏函数意义
偏函数就是把原函数的部分参数固定住,返回一个新的函数,等以后再补剩下的参数。
它的重点是:
- 一次可以固定多个参数(而不是一个一个固定)
- 参数什么时候补都行,不需要拆成一参链式函数
- 它不是柯里化,但作用类似:抽离复用、提前绑定参数
原函数:
function sum(a, b, c) {
return a + b + c;
}
偏函数应用:
const add10 = partial(sum, 10); // 固定第一个参数
add10(2, 3) // 15
偏函数相当于提前把 a=10 固定了
⚡ 实现偏函数
最简单易背的版本:
function partial(fn, ...fixedArgs) {
return function (...restArgs) {
return fn(...fixedArgs, ...restArgs);
};
}
用法:
const multiply = (a, b, c) => a * b * c;
const double = partial(multiply, 2);
double(3, 4); // 24
一次固定多个参数:
const times6 = partial(multiply, 2, 3);
times6(4); // 24
🧠 偏函数应用
① 固定 API 参数(常用)
function request(method) {
return (url, data) => fetch(url, { method, body: data });
}
const get = request('GET');
const post = request('POST');
get('/users');
post('/users', { name: '二二四一同志' });
② 日志函数预绑定前缀(场景经典)
const log = partial(console.log, '[MyApp]');
log('启动成功');
// => [MyApp] 启动成功
③ UI 事件绑定
function handleChange(field, value) {
form[field] = value;
}
const updateUsername = partial(handleChange, "username");
updateUsername("Alice");
④ React 中高频用法(绑定参数)
<button onClick={partial(handleClick, item.id)}>删除</button>
偏函数就是对一个函数预先绑定部分参数,返回一个新的“定制化”函数。偏函数一次可以固定多个参数,补齐剩下的参数后执行原函数。
🔥 偏函数 vs 柯里化
| 特性 | 柯里化(Currying) | 偏函数(Partial) |
|---|---|---|
| 参数处理 | 把函数拆成一参链式函数 | 预先固定部分参数 |
| 调用方式 | f(a)(b)(c) | f(a, b)(c) 或 g(c) |
| 参数收集规则 | 逐步收集,每次只能给一个(经典定义) | 一次可以给多个剩余参数 |
| 适用场景 | 函数组合、函数式编程 | 预绑定部分参数、构造专用函数 |
| 学术地位 | 理论较重(λ calculus) | 更实用更业务化 |
偏函数是固定一部分参数;柯里化是拆分成一参函数链式调用。二者都能实现参数预置,但机制完全不同。