Appearance
2632. 柯里化
ts
/**
* 请你编写一个函数,它接收一个其他的函数,并返回该函数的 柯里化 后的形式。
* 柯里化 函数的定义是接受与原函数相同数量或更少数量的参数,并返回另一个 柯里化 后的函数或与原函数相同的值。
* 实际上,当你调用原函数,如 sum(1,2,3) 时,它将调用 柯里化 函数的某个形式,如 csum(1)(2)(3), csum(1)(2,3), csum(1,2)(3),或 csum(1,2,3) 。所有调用 柯里化 函数的方法都应该返回与原始函数相同的值。
*/
function curry(fn: Function): Function {
return function curried(...args: any[]): any {
if (args.length >= fn.length) {
return fn(...args);
}
return function (...nextArgs: any[]) {
return curried(...args.concat(nextArgs));
};
};
}核心机制
柯里化的本质是参数累积,不是链式调用。每次调用返回一个「收集了更多参数」的新函数,直到参数数量达到原函数的形参数量(fn.length)时,才执行原函数并返回结果。
fn.length 在这里扮演了关键角色——它是 JavaScript 函数的 length 属性,表示函数定义的形参个数。这个值在函数创建时就确定了,与调用时实际传入多少个参数无关。
闭包的作用
curried 闭包需要记住两个东西:
- 原函数
fn(外层作用域) - 已收集的参数
args(当前函数参数)
每次参数不够时,返回的新函数通过 args.concat(nextArgs) 把新旧参数合并,再递归调用 curried。这个递归不是尾递归,但因为实际调用深度受限于参数总数,不会堆栈溢出。
灵活性
这个实现支持 csum(1)(2,3) 和 csum(1,2,3) 混用,因为每次参数检查用的是 >= 而不是 ===——如果一次传多了,也直接执行。
和 bind 的区别:bind 也做参数预绑定,但它总是返回新函数,不会自动执行。curry 在参数齐全时会立即执行原函数。
