0

请在回答之前阅读整个问题。

我在看你不能在压力下做 JavaScript 测验,并得到了关于对数组中的值求和的问题。我编写了以下函数(最初没有 console.log 语句),它的行为与输入 [[1,2,3],4,5] 不一样 - 返回 10 而不是 15。最终我想出了如何修复它 - 在 n 和 sum 前面添加 var。我在 Firefox 的 Scratchpad 中调试时一直在执行此操作,在 Firebug 中查看控制台输出。

function arraySum(i) {

    // i will be an array, containing integers, strings and/or arrays like itself.
    // Sum all the integers you find, anywhere in the nest of arrays.

    n=0;
    sum=0;
    console.log(i.length)
    while(n<i.length){

        console.log("i["+n+"]="+i[n]);

         if(i[n].constructor==Array){
             console.log("array n="+n)
            sum+=arraySum(i[n]);
            console.log("out array n="+n)
        }
        else if(typeof(i[n])=="number"){
            console.log("number")
        sum+= i[n];

        }
        n++;
        console.log("sum="+sum+" n="+n)
    }
    return sum

}
console.log(arraySum([1,[1,2,3],2] ) );

输出是

start
Scratchpad/1 (line 9)
3
Scratchpad/1 (line 17)
i[0]=1
Scratchpad/1 (line 20)
number
Scratchpad/1 (line 28)
sum=1 n=1
Scratchpad/1 (line 33)
i[1]=1,2,3
Scratchpad/1 (line 20)
array n=1
Scratchpad/1 (line 23)
3
Scratchpad/1 (line 17)
i[0]=1
Scratchpad/1 (line 20)
number
Scratchpad/1 (line 28)
sum=1 n=1
Scratchpad/1 (line 33)
i[1]=2
Scratchpad/1 (line 20)
number
Scratchpad/1 (line 28)
sum=3 n=2
Scratchpad/1 (line 33)
i[2]=3
Scratchpad/1 (line 20)
number
Scratchpad/1 (line 28)
sum=6 n=3
Scratchpad/1 (line 33)
out array n=3
Scratchpad/1 (line 25)
sum=7 n=4
Scratchpad/1 (line 33)
7

所以最终我发现当函数被递归调用时,外部函数的 n 变量被重置为 0 并修改为 3,所以当它退出时,而不是再循环一次(如果 n 是 2 它将这样做)它离开功能。这一切都是有意义的,直到您考虑 sum 变量,它应该在相同的条件下:在递归调用中重置为 0,然后在退出函数的递归调用时结束为 6,

所以我的问题是:

为什么我得到 7 而不是 6?

4

2 回答 2

2

尝试在调试器中执行它。我尽量做到精确而不一步一步:

  • 结束第 1 次迭代:sum = 1, n = 1
  • “进入”子数组:sum += arraySum(i[n]);等价:sum = sum + arraySum(i[n]);此时sum = 1,arraySum需要确定的值。
  • 子数组正确计算为 6,因为nsum被重置。
  • 所以项目符号 2 的表达式计算为 sum = 7
  • n不会从上一次调用中重置,并且指向数组末尾之外。因此返回值 7。

为了使代码按预期工作,您必须使用var并且错误地将以下内容括在括号中:

否则 if(typeof (i[n]=="number") )
所以typeof适用于i[n]=="number"哪个不是你想要的(它总是boolean!)

此外,我建议a作为输入数组、i迭代器和n长度(n = a.length)。

于 2013-10-23T10:35:21.983 回答
1

ECMA-262(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Language_Resources)定义:

11.13.2 复合赋值(op=)

产生式 AssignmentExpression : LeftHandSideExpression AssignmentOperator AssignmentExpression,其中 AssignmentOperator 为 @=,@ 表示上述运算符之一,计算如下:

  1. 令 lref 为评估 LeftHandSideExpression 的结果。
  2. 令 lval 为 GetValue(lref)。
  3. 令 rref 为评估 AssignmentExpression 的结果。
  4. 设 rval 为 GetValue(rref)。
  5. 令 r 为将运算符 @ 应用于 lval 和 rval 的结果。
  6. 如果以下条件都为真,则抛出 SyntaxError 异常:
    • 类型(lref)是参考是真的
    • IsStrictReference(lref) 为真
    • Type(GetBase(lref)) 是环境记录
    • GetReferencedName(lref) 是“eval”或“arguments”
  7. 调用 PutValue(lref, r)。
  8. 返回 r。

在您的代码示例中,这sum += arraySum(i[n])意味着:

  1. 获取总和变量
  2. 获取 sum 的值并将其临时存储在lval内部变量中
  3. 获取对函数调用 arraySum(i[n]) 的引用
  4. 获取函数调用的结果并将其存储在rval内部变量中
  5. 添加lvalrval
  6. 确保没有问题
  7. 将结果存储在您的总和中
  8. 也返回这个结果

您遇到了递归问题,因为当您第二次调用 arraySum 时,您覆盖了全局变量nsum. 覆盖sum不是问题,因为您使用+=了运算符,但是在将 n 倒回到 4 后结束了对 arraySum 的第一次调用。

于 2013-10-23T10:55:47.977 回答