Javascript递归示例所需的解释

时间:2016-03-31 19:22:12

标签: javascript recursion

我在Javascript Recursion中经历了一些例子。

我在此页面中找到了以下代码:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions#Recursion

function foo(i) {
  if (i < 0)
        return;
  console.log('begin:' + i);
  foo(i - 1);
  console.log('end:' + i);
}
foo(3);

代码输出:

// begin:3
// begin:2
// begin:1
// begin:0
// end:0
// end:1
// end:2
// end:3

任何人都可以解释输出(特别是'结束'之后的值)吗?

谢谢!

3 个答案:

答案 0 :(得分:1)

end控制台日志是每个递归调用的完成:

---- Invocation 1 ----
begin:3
        ---- Invocation 2 ----
        begin:2
            ---- Invocation 3 ----
            begin:1
                ---- Invocation 4 ----
                begin:0
                end:0
                ---- Invocation 4 ----
            end:1
            ---- Invocation 3 ----
        end:2
        ---- Invocation 2 ----
end:3
---- Invocation 1 ----

答案 1 :(得分:0)

首先,您从i = 3开始。要控制台begin: 3。下一行用i = 2执行函数并显示begin: 2等等。如果执行了另一个函数中的函数,则函数的父级可以显示end: i。但是,当功能end: i未完成时,您无法看到i - 1

更多信息:https://en.wikipedia.org/wiki/Recursion_%28computer_science%29

答案 2 :(得分:0)

要理解这段代码,你需要理解&#34;堆栈&#34;在JavaScript中。查找有关此主题的视频可能会有所帮助。堆栈就像一个&#34;做&#34;名单。无论何时你需要调用一个函数,它都会被放在&#34;来做&#34; list /&#34;调用堆栈&#34;,直到函数完成。函数以两种方式之一完成:一)它返回一些东西或两个)它完全运行到函数内部代码的末尾。

单步执行示例中的代码:

  1. 堆栈是空的。
  2. foo(3)被调用。
  3. foo(3)被放置在堆栈上。
  4. 现在,堆栈看起来像这样:
  5.   

    FOO(3);

    1. JavaScript说,&#34;好吧,在我的&#34;顶部&#34;做&#34; list,有函数foo(3),所以它开始执行这个foo(3):
    2. 3不小于0,因此该功能不返回任何内容并继续。
    3. 执行console.log(&#39;开始:&#39; + 3)。
    4. 在下一行,您将再次调用一个函数。这是它变得棘手的地方,所以要注意。
    5. 此时,我= = 3,所以foo(i-1)是foo(2);
    6. 为了完成foo(3),JavaScript需要首先执行刚刚调用的foo(2)中的指令,因此foo(2)被放置在调用堆栈上。所以,foo(2)被放在&#34;做&#34;列表/调用堆栈,但foo(3)仍在那里。
    7. 调用堆栈现在看起来像这样:
    8.   

      FOO(2);
        FOO(3);

      1. JavaScript现在开始执行foo(2)。
      2. 2不小于0,因此代码继续。
      3. JavaScript执行console.log(&#39;开始:&#39; + 2);
      4. i - 1 === 1,所以,JavaScript调用foo(1);
      5. 调用堆栈现在看起来像这样:
      6.   

        FOO(1);
          FOO(2);
          FOO(3);

        1. JavaScript必须先完成foo(1)才能继续使用foo(2)。
        2. 重复此过程,直到调用堆栈如下所示:
        3.   

          FOO(-1);
            FOO(0);
            FOO(1);
            FOO(2);
            FOO(3);

          1. 现在,让我们来看看单步执行foo(-1)中的代码:
          2. -1小于0,因此foo(-1)命中其return语句。它返回undefined。它没有到达&#39; console.log&#39;声明。因为它返回了一些东西,所以函数运行完毕。它从&#34;的顶部弹出来做#34; list /&#34; call stack&#34;
          3. 调用堆栈现在看起来像这样:
          4.   

            FOO(0);
              FOO(1);
              FOO(2);
              FOO(3);

            1. foo(0)调用了foo(-1)。现在foo(-1)已经完成,foo(0)可以继续。
            2. 调用foo(-1)后的代码行是:console.log(&#39; end:&#39; + 0),所以接下来执行。
            3. foo(0)从未点击过返回语句,但它一直运行到函数结束,因此该函数现在已经完成。它从调用堆栈中弹出。
            4. 调用堆栈现在看起来像这样:
            5.   

              FOO(1);
                FOO(2);
                FOO(3);

              1. 代码以与上面相同的模式继续。它将继续执行foo(1)直到它完成。然后它将转到它在foo(2)中停止的位置并继续运行。当foo(2)完成时,它也会弹出调用堆栈。
              2. 最后,foo(3)有执行foo(2)的指令。由于foo(2)执行完毕,foo(3)可以继续其余的代码。
              3. 当foo(3)完成时,调用堆栈再次为空。
              4. 因此,console.log(&#34; begin:..)语句在你的堆栈上执行,而console.log(&#34; end:..)语句在路上执行堆栈。