【问题标题】:I don't understand how this recursion is working in javascript我不明白这个递归是如何在 javascript 中工作的
【发布时间】:2021-04-04 21:30:39
【问题描述】:

function countdown(n) {
    if (n < 1) {
      return [];
    } else {
      const arr = countdown(n - 1);
      arr.unshift(n);
      return arr;
    }
  }
console.log(countdown(10));

现在我使用 vs 代码对其进行了调试,它向我展示了在开始时 n=10 时唯一被执行的行是“arr = countdown(n - 1);”行,然后将其存储在调用堆栈中,当 n 最终变为 0 时,函数返回 [] 但不是退出 if else 循环,而是运行 arr.shift(n) for n 从 1 到 10,然后返回数组.我不明白它是如何工作的。

【问题讨论】:

  • 您的问题实际上很好地解释了正在发生的事情。我想也许你错过了函数调用有点像洋葱层一样的包裹。所以最里面的调用 (n=0) 有 10 个调用围绕它,当它们开始返回洋葱解包时,外部函数调用依次继续(到下一行)。
  • 我认为以下 Q/A 可能会帮助您更好地理解递归,您可以在这里应用相同的概念 - stackoverflow.com/questions/66225803/…

标签: javascript


【解决方案1】:

第一次帮助我理解递归的是字面上的内联函数调用。用函数体替换函数调用。

为了使这更简单一点,我们将添加一个肮脏的小助手并稍微简化倒计时。

Array.prototype.prepend = function(...args){
  this.unshift(...args);
  return this;
}

// so can write countdown() as:

function countdown(n) {
  if (n < 1) {
    return [];
  } else {
    return countdown(n - 1).prepend(n);
  }
}

// or even shorter:
function countdown(n) {
  return (n < 1) ? [] : countdown(n - 1).prepend(n);
}
// this version is easy to inline!

因此,此时我们还没有更改代码逻辑中的任何内容,我们只是将 unshift 部分移到了一个新方法中,我们定义该方法是为了让我们的生活更轻松。

现在让我们内联递归:

const result = countdown(5);开始,内联倒计时(5),我们得到const result = (5 &lt; 1 ? [] : countdown(5 - 1).prepend(5));

...内联倒计时(5 - 1):

const result = (5 < 1 ? [] :
  (4 < 1 ? [] :
    countdown(4 - 1).prepend(4)
  ).prepend(5));

...内联倒计时(4 - 1):

const result = (5 < 1 ? [] :
  (4 < 1 ? [] :
    (3 < 1 ? [] :
      countdown(3 - 1).prepend(3)
    ).prepend(4)
  ).prepend(5));

等等,一直到这个:

const result = (5 < 1 ? [] :
  (4 < 1 ? [] :
    (3 < 1 ? [] :
      (2 < 1 ? [] :
        (1 < 1 ? [] :
          (
            // here the else-block won't be called, so nothing to add anymore. 
            // The recursion is terminated
            0 < 1 ? [] : countdown(0 - 1).prepend(0) 
            // now it's going back up:
          ).prepend(1)
        ).prepend(2)
      ).prepend(3)
    ).prepend(4)
  ).prepend(5));

这是否使其可见,递归如何/为什么首先深入到 n==0 return [],然后再向上走并预先添加/取消移动所有数字。

【讨论】:

  • 哦,现在我终于明白了。该死的,这是理解这一点的好方法。因此,据我了解,该函数首先递归地获取所有值并将其递归地添加到堆栈中,然后将值添加到数组中然后返回它。
猜你喜欢
  • 2012-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-15
  • 2016-10-27
相关资源
最近更新 更多