使用递归的JavaScript范围不规则

时间:2013-10-23 10:13:45

标签: javascript recursion scope

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

我看着你在压力测验下不能做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?

2 个答案:

答案 0 :(得分:2)

尝试在调试器中执行它。我试着精确而不是一步一步:

  • 结束第一次迭代:sum = 1,n = 1
  • “进入”子阵列:sum += arraySum(i[n]);等效:sum = sum + arraySum(i[n]);此时,sum = 1,需要确定arraySum的值。
  • 子阵列正确计算为6,因为nsum已重置。
  • 因此,子弹2的表达式评估为sum = 7
  • n未从上一次调用中重置,并指向超出数组末尾的位置。因此返回值7。

要使代码按预期工作,必需使用var,并且您错误地将以下内容括起来:

else if(typeof (i[n]=="number") )
因此typeof适用于i[n]=="number",这不是您想要的(始终为boolean!)

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

答案 1 :(得分: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.   
  3. 让lval成为GetValue(lref)。
  4.   
  5. 让rref成为评估AssignmentExpression的结果。
  6.   
  7. 让rval为GetValue(rref)。
  8.   
  9. 设r是将operator @应用于lval和rval的结果。
  10.   
  11. 如果满足以下条件,则抛出SyntaxError异常:   
        
    • Type(lref)是Reference is true
    •   
    • IsStrictReference(lref)为真
    •   
    • 类型(GetBase(lref))是环境记录
    •   
    • GetReferencedName(lref)是“eval”或“arguments”
    •   
  12.   
  13. 调用PutValue(lref,r)。
  14.   
  15. 返回r。
  16.   

代码sum += arraySum(i[n])的示例中的含义是:

  1. 获得和变量
  2. 获取总和的值并将其临时存储在lval内部变量
  3. 参考函数调用arraySum(i [n])
  4. 获取函数调用的结果并将其存储在rval内部变量
  5. 添加lvalrval
  6. 确保没有问题
  7. 将结果存储在您的总和中
  8. 也会返回此结果
  9. 你的递归问题,因为当你第二次调用arraySum时,你覆盖了全局变量nsum。覆盖sum没问题,因为您使用了+=运算符,但是在将n回放到4之后,您终止了对arraySum的第一次调用。