柯里化介绍
首先来看一个简单的场景,计算 a + b + c。正常写法是 add(1,2,3),但柯里化会把它变成 add(1)(2)(3)——把多参数的函数,拆成一系列单参数函数的链式调用,每次调用只传部分参数,直到传完所有参数才执行最终计算。」
// 普通多参数函数
function add(a, b, c) {
return a + b + c;
}
console.log(add(1, 2, 3)); // 6
// 柯里化后的函数
function curriedAdd(a) {
return function(b) {
return function(c) {
return a + b + c;
};
};
}
console.log(curriedAdd(1)(2)(3)); // 6(链式调用,分步传参)
手写柯里化
要实现通用的柯里化函数,必须抓住 3 个核心点:
- 收集参数:用闭包保存每次传入的参数,直到收集够「原函数需要的参数个数」;
- 判断触发执行:每次传参后,判断已收集的参数个数是否 >= 原函数的形参个数,够了就执行原函数,不够就返回新函数继续收集;
- 保持原函数的 this 指向和参数传递:确保执行原函数时,this 指向正确,且能接收剩余参数。
我们要写一个 curry 函数,接收「原函数」作为参数,返回「柯里化后的函数」。用法:const curriedFn = curry(原函数)
首先,curry 函数接收原函数 fn,返回一个新函数 curried。用闭包保存已收集的参数 args:
function curry(fn) {
// 用闭包收集每次传入的参数
const args = [];
// 返回柯里化后的函数,每次调用时接收部分参数
return function curried(...rest) {
// 把本次传入的参数加入 args(收集参数)
args.push(...rest);
// 核心判断:已收集的参数个数 >= 原函数的形参个数?
if (args.length >= fn.length) {
// 够了,执行原函数,返回结果
return fn(...args);
} else {
// 不够,返回 curried 函数,继续收集参数
return curried;
}
};
}
测试结果
// 原函数:3个形参
function add(a, b, c) {
return a + b + c;
}
// 柯里化处理
curriedAdd = curry(add);
// 测试1:分步传参(每次1个)
console.log(curriedAdd(1)(2)(3)); // 6(符合预期)
// 测试2:部分批量传参
console.log(curriedAdd(1, 2)(3)); // 6(符合预期)
console.log(curriedAdd(1)(2, 3)); // 6(符合预期)
// 测试3:一次性传参(和原函数用法一致)
console.log(curriedAdd(1, 2, 3)); // 6(符合预期)