标准答案
- 柯里化 currying 是把一个多参数函数转换成可以分批接收参数的函数,例如把 fn(a, b, c) 转换成 fn(a)(b)(c) 或 fn(a, b)(c)。
- 手写 curry 的核心是收集参数。当已经收集到的参数数量达到原函数需要的参数数量时,执行原函数;否则返回一个新函数继续接收剩余参数。
- 偏函数 partial application 是预先固定一部分参数,返回一个等待剩余参数的函数。它不要求把函数拆成连续单参数调用。
- 两者的区别在关注点:柯里化强调参数逐步收集和函数组合,偏函数强调复用已有函数并预填部分参数。实现时还要注意 this、默认参数、剩余参数和 fn.length 的边界。
题目解析
柯里化最常见的判断条件是 args.length >= fn.length。这个判断适合普通固定参数函数,但默认参数、剩余参数会改变 length,因此工程工具函数通常允许显式传入 arity。
this 透传是手写题里的基础边界。包装函数如果直接 fn(...args),对象方法被柯里化后可能丢失调用上下文;用 apply 可以把当前调用的 this 继续传给原函数。
柯里化适合参数复用、延迟执行、函数组合和管道处理。普通业务代码不必为了形式感强行柯里化;当它能减少重复参数或让组合更清楚时再使用。
代码示例
下面示例展示支持分批传参的 curry,以及只固定部分参数的 partial。
JavaScript
function curry(fn) {
function curried(...args) {
const context = this
if (args.length >= fn.length) {
return fn.apply(context, args)
}
return function collect(...nextArgs) {
return curried.apply(context, args.concat(nextArgs))
}
}
return curried
}
function partial(fn, ...presetArgs) {
return function partiallyApplied(...restArgs) {
return fn.apply(this, presetArgs.concat(restArgs))
}
}
const add = (a, b, c) => a + b + c
const curriedAdd = curry(add)
curriedAdd(1)(2)(3) // 6
curriedAdd(1, 2)(3) // 6
const addTen = partial(add, 10)
addTen(2, 3) // 15常见误区
- 把柯里化和偏函数完全等同。
- 只支持一次传一个参数,不支持 fn(a, b)(c) 这种分批传参。
- 忽略 this 透传,导致方法柯里化后上下文丢失。