函数在递归期间调用

时间:2017-08-29 13:42:38

标签: javascript recursion

最近我一直在努力理解递归以及一切实际如何工作,所以我写了这个js函数

function checkScope(times){
    if(times == 1){
        console.log(`Times is ${times}`);
    }else{
        checkScope(times-1);
        console.log(`Times is ${times}`)
    }
}

根据我的理解,我相信如果我用以下方式调用此函数:

checkScope(3)

首先执行else块中的第一个语句,然后再次调用该函数,然后发生同样的事情,这次变量times = 1,所以我应该得到“Times is 1”的日志。也许当控制权转移回调用函数时,最后一行代码执行:

Times is [I dont know what times should be at this time :(]

但是当我运行时,我最终得到了

Times is 1
Times is 2
Times is 3

作为我的输出,请我解释一下。

6 个答案:

答案 0 :(得分:2)

它与console.log()checkScope()函数调用的顺序相关。由于您首先调用checkScope()函数,因此最终控制台将记录最后一项。

所以你应该按如下方式替换行的顺序:



function checkScope(times){
    if(times == 1){
        console.log(`Times is ${times}`);
    }else{
        console.log(`Times is ${times}`)
        checkScope(times-1);
    }
}

checkScope(3);




为了更好地理解,请检查一下。



function checkScope(times){
    console.log("checkScope("+times+") called.");
    if(times == 1){
        console.log(`Times is ${times}`);
    }else{
        console.log(`Times is ${times}`)
        checkScope(times-1);
    }
    console.log("checkScope("+times+") returned.");
}

checkScope(3);




答案 1 :(得分:2)

  

也许当控制权转移回调用函数时......

...然后你需要记住那是什么。在这种情况下,第三个调用(记录1)确实返回到第二个调用,该调用继续在那里的console.log语句。那里times没有什么价值?要理解的主要问题是每个调用都维护其局部变量 - 在第二个调用中,times2。然后在记录之后它从第二次调用返回到第一次调用。在那里,times的值为3,会被记录。然后它最终从第一次调用返回到调用站点checkScope(3),然后脚本结束。

答案 2 :(得分:1)

很简单。请参阅,在第4行console.log调用后调用checkScope。这会导致所有console.log调用被推迟到递归解析的时间(times == 1)。所以这里会发生什么:

  1. checkScope(3);
  2. checkScope(2); //在第4行
  3. checkScope(1); //在第4行
  4. 的console.log(Times is ${times}); //第二行有1个
  5. console.log(Times is ${times})//在第5行有2个
  6. console.log(Times is ${times})//在第5行有3个

答案 3 :(得分:1)

您始终可以使用调试器查看流程,无论如何请查看以下说明

checkScope(3)
    since times = 3
    checkScope(2) is called
        since times = 2
        checkScope(1) is called
             logs: Times is 1 
             returns
        logs: Times is 2
        returns 
    logs: Times is 3
    returns

我希望这可以帮助您理解代码

答案 4 :(得分:1)

所以让我们一步一步来,你打电话给checkScope(3)

  1. checkScope(3)被称为
  2. 如果(3 == 1)变为false,那么我们转到else块代码
  3. else块中的第一行调用checkScope(3-1)*
  4. checkScope(2)被称为
  5. 如果(2 == 1)变为false,那么我们转到else块代码
  6. else块中的第一行调用checkScope(1)**
  7. checkScope(1)被称为
  8. 如果(1 == 1)为真,那么我们console.log(“时间为1”),checkScope(1)函数就完成了。
  9. 我们返回**因为我们的checkScope(2)实例尚未结束
  10. 我们console.log(“时间是2”)所以checkScope(2)现在已经完成,我们转到*。
  11. 我们console.log(“时间是3”),checkScope(3)现已完成。
  12. 一般来说,你应该记住的是有一个叫做“调用堆栈”的东西。您可以将其视为一个堆栈,其中所有函数都被称为go。顶部的功能是当前执行的功能。函数完成后,它会从堆栈中退出,然后下一个函数位于顶部。

    在checkScope(3)中,当调用checkScope的新实例时,它将被置于checkScope(3)上。因此,在调用checkScope(2)的步骤4中,调用堆栈将是:

    1. checkScope(2)
    2. checkScope(3)
    3. 在第7步,调用堆栈将是:

      1. checkScope(1)
      2. checkScope(2)
      3. checkScope(3)
      4. 在步骤8,调用堆栈是:

        1. checkScope(2)
        2. checkScope(3)
        3. 在步骤10,调用堆栈:

          1. checkScope(3)
          2. 当我们到达第11步时,调用堆栈为空,因为所有调用的函数现已终止。

答案 5 :(得分:1)

这使它更清楚

因此,由于在= = 1之前的前一个函数调用都没有到达它们的最后一行,在次= = 1之后,所有其他函数执行它们的最后几行代码,这些代码就是console.log()行时变量值。