答案是通过在返回的函数上定义 tostring 和 valueof 方法,使其在隐式类型转换时返回累加和,从而实现 add(1)(2)(3) == 6;二者必须为返回原始值的函数,且均返回当前 sum,以适配数值和字符串上下文。

实现 add(1)(2)(3) == 6 这类无限累加柯里化函数,核心不在“多层调用”本身,而在于让返回的函数在需要数值时自动给出累加结果——这靠的是 JavaScript 的隐式类型转换机制,关键钩子就是 toString 和 valueOf。
为什么 toString / valueOf 能被自动触发
JavaScript 在特定上下文中会悄悄把对象(包括函数)转成原始值:
-
数值上下文:比如
==、+(左边是数字)、Math.max等,优先调用valueOf();若它返回的不是原始值,再 fallback 到toString() -
字符串上下文:比如
"" + fn、console.log(fn)、模板字符串`${fn}`,优先调用toString() -
add(1)(2)(3) == 6中的==就是典型的数值比较上下文,所以引擎会先尝试valueOf();如果没定义或返回对象,就接着找toString()
如何正确挂载 toString / valueOf
必须把它们定义在**返回的函数对象上**,而不是闭包内部变量里。常见错误是只写 tmp.toString = ... 却忘了 tmp.valueOf = ...,导致 == 不稳定(因为 == 优先查 valueOf):
- 定义
toString是为了兼容console.log(add(1)(2))、"" + add(1)(2)等场景 - 定义
valueOf是为了让==、===(严格相等不触发隐式转换,但==会)、Number(add(...))等能直接拿到数字 - 两者都返回当前累加和(如
return sum),保持行为一致,避免陷阱
一个健壮可运行的实现
下面代码支持 add(1)(2)(3) == 6、add(1)(2)(3) + 0 === 6、console.log(add(1)(2)(3)) 输出 6:
function add(x) {
let sum = x;
function curried(y) {
sum += y;
return curried;
}
curried.toString = curried.valueOf = () => sum;
return curried;
}
注意:curried.toString 和 curried.valueOf 必须是函数,且返回原始值(这里是 number)。不能写成 curried.toString = sum(赋值而非函数),否则隐式转换会失败。
实际使用中的典型表现
你可以这样验证效果:
-
add(1)(2)(3) == 6→ true(==触发valueOf) -
add(1)(2)(3) + ""→ "6"(字符串拼接触发toString) -
console.log(add(1)(2)(3))→ 控制台显示 6(console.log对非原始值会调用toString) -
Boolean(add(1)(2)(3))→ true(因为valueOf返回 6,转布尔为 true)











