前言
前面写过关于JavaScript的this指向的基础文章,链接:juejin.cn/post/751796…
今天我们继续来讲讲闭包的应用场景之一:函数柯里化
什么是函数柯里化?
函数柯里化(Currying) 是一种函数编程技巧,它的核心思想是:
把一个接受多个参数的函数,转换成一系列只接受一个参数的函数链。
例如,原本一个函数是这样调用的:
add(1, 2, 3); // 返回 6
经过柯里化后,可以写成:
curriedAdd(1)(2)(3); // 返回 6
或者:
curriedAdd(1)(2, 3); // 返回 6
柯里化的本质就是分步传参,每一步都返回一个新的函数,直到所有参数都收集完毕,才真正执行原始函数。
闭包在柯里化中的作用
要实现柯里化,离不开一个关键工具:闭包(Closure) 。
闭包的作用是:
让函数能够“记住”之前传入的参数,并在后续调用中继续使用它们。
来看一个简单的例子:
function curriedAdd(a) {
return function(b) {
return function(c) {
return a + b + c;
};
};
}
我们来一步步分析这段代码:
curriedAdd(1)→ 返回一个新函数,并记住a = 1- 再调用这个新函数
(2)→ 又返回一个新函数,并记住b = 2 - 最后再调用
(3)→ 计算a + b + c = 1 + 2 + 3 = 6
这里的“记住”,正是通过闭包实现的。每一层函数都能访问到外层函数传进来的参数。
通用的柯里化函数
为了方便地对任意函数进行柯里化,我们可以编写一个通用的柯里化函数:
function curry(fn) {
return function curried(...args) {
// 如果传入的参数个数 >= 原始函数需要的参数个数,则直接执行
if (args.length >= fn.length) {
return fn.apply(this, args);
} else {
// 否则返回一个新函数,继续等待剩余参数
return function (...moreArgs) {
return curried.apply(this, args.concat(moreArgs));
};
}
};
}
使用示例:
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
详细解析:
-
输入检查:
fn是要被柯里化的原始函数。例如,add(a, b, c)需要三个参数。 -
返回一个闭包:
curry函数返回一个新的函数curried。这个新函数使用了可变参数(...args),可以接受任意数量的参数。 -
判断参数数量是否足够:
- 使用
fn.length获取原始函数期望的参数个数。比如对于add(a, b, c),fn.length就是 3。 - 使用
args.length检查当前已接收的参数数量。
- 使用
-
如果参数足够:
- 直接调用原始函数
fn并返回结果。这里使用apply方法来确保参数以正确的格式传递,并且支持上下文(this)的正确性。
- 直接调用原始函数
-
如果参数不足:
- 返回一个新的匿名函数,该函数期待接收更多的参数(
...moreArgs)。 - 当这个新的匿名函数被调用时,它会把已经收集到的参数 (
args) 和新收到的参数 (moreArgs) 结合起来,再次调用curried自身(递归)。这一步实现了参数的逐步积累直到所有参数都收集完毕才执行原始函数add()。
- 返回一个新的匿名函数,该函数期待接收更多的参数(
函数柯里化是函数式编程的重要概念,也是闭包的一个经典应用。它通过逐步传参的方式,让函数更加灵活、可复用、可组合。
总结
函数柯里化是函数式编程的重要概念,也是闭包的一个经典应用。它通过逐步传参的方式,让函数更加灵活、可复用、可组合。
✅ 柯里化的优势:
- 参数复用:固定部分参数,生成新函数。
- 延迟执行:支持分阶段传参,适合异步或交互场景。
- 提高可读性:拆分复杂函数,增强模块化和可维护性。
- 函数式编程基础:为组合函数、管道操作等高级技巧提供基础。