JS实现FreeCodeCamp Arguments Optional挑战返回'23'而非undefined问题排查
代码Bug定位与逻辑拆解
你遇到的两个核心问题解答
问题1:为什么[3]没有被checkNum判定为非法值?
你遇到返回'23'的场景,实际走的是柯里化调用路径addTogether(2)([3]),不是直接传两参的addTogether(2, [3])。
- 你的
checkNum函数只定义在外层addTogether的作用域里,内层返回的匿名函数完全没有调用checkNum做参数校验。当外层只收到1个合法数字参数时,会直接返回一个闭包函数;这个函数拿到入参[3]时,根本不会检查它是不是数字,直接做加法运算,自然不会触发checkNum的非法值判断。 - 如果是直接传两参的场景
addTogether(2, [3]),外层逻辑是可以正确识别[3]为非法值、返回undefined的。
问题2:字符串'23'是哪个环节生成的?
这个值完全来自内层闭包函数的无校验加法运算:
JS的+运算符有两种模式:数值加法、字符串拼接。当其中一个操作数是对象(比如数组[3])时,会优先把对象转成原始字符串值——[3]调用自身的字符串转换方法会得到'3',此时运算就从数值加法变成了字符串拼接:数字2被转成字符串'2',和'3'拼接后就得到了'23'。
当前代码的隐藏语法bug
代码里还有一个很容易踩坑的写法问题:
- 那行
if (typeof num1 === 'number' && typeof num2 === 'number');的末尾多写了一个分号。
这个分号会让JS把if后面直接接一个空语句,完全不会绑定后面的代码块。哪怕这个if的条件不成立,后面花括号里的return arguments[0] + arguments[1]也会无条件执行。目前因为前面已经有参数校验拦截了非法值,暂时没暴露问题,但一旦调整校验顺序,就会出现非法值直接参与运算的问题。
你看不懂的嵌套返回逻辑通俗解释
你看到的那段代码,本质是在实现题目要求的“参数可选”能力,拆成两步就很好理解:
- 外层调用先判断传了几个参数:
- 传了2个及以上参数的话,走常规校验逻辑:两个参数都是数字就返回和,否则返回
undefined。 - 只传了1个参数的话,先检查这个参数是不是合法数字:
- 不是合法数字,直接返回
undefined。 - 是合法数字,此时不能直接返回结果——因为用户可能还没传第二个要相加的数,这时候就返回一个新的函数给用户,让用户可以再调用一次,把第二个参数传进来。
- 不是合法数字,直接返回
- 传了2个及以上参数的话,走常规校验逻辑:两个参数都是数字就返回和,否则返回
- 返回的内层函数的作用:
它会接住用户后续传进来的第二个参数b,先检查b是不是合法数字:- 是合法数字,就把之前存好的第一个数
a和b加起来返回。 - 不是合法数字,就直接返回
undefined——因为JS里函数没写return语句时,默认返回undefined,所以不需要特意写判断分支。
简单说,这种“第一次调用只传一个数,返回一个函数等着接第二个数,接齐了就算和”的模式,就是闭包最常见的用法:内层函数能记住外层调用时存的第一个数a,等第二个参数到位了再完成计算。
- 是合法数字,就把之前存好的第一个数
修正后的参考实现
function addTogether() { function checkNum(x) { return typeof x === 'number' ? x : undefined; } // 处理单参数分支 if (arguments.length === 1) { const a = checkNum(arguments[0]); if (typeof a !== 'number') return undefined; // 返回内层函数,接住第二个参数同时做合法性校验 return function(b) { const validB = checkNum(b); return typeof validB === 'number' ? a + validB : undefined; } } // 处理多参数分支 if (arguments.length > 1) { const a = checkNum(arguments[0]); const b = checkNum(arguments[1]); return typeof a === 'number' && typeof b === 'number' ? a + b : undefined; } }
内容的提问来源于stack exchange,提问作者kio777kio
相关产品推荐
相关产品推荐

