计算函数在 JS 中被递归调用了多少次

Counting how many times a function has been called recursivly in JS

我有一个家庭作业,我应该在 JavaScript 中编写一个伪随机数生成器。这是我写的代码位

var k = 0;

var slump = function(n, k) {
  if (k < 10) {
  console.log("stop");
  }
  else {
    k++;
    console.log((5*n + 1) % 8);
    return slump((5*n + 1) % 8, k);
  }
};

slump(0);

k 应该保存函数被调用的次数。但是,它不只是 运行 函数十次,它只是保持 运行。有什么办法可以解决这个问题吗?

无论何时编写递归函数,都需要确保:

  1. 有一个基本情况(在您的情况下,当 console.log 语句运行时)
  2. 函数朝着基本情况前进,并且
  3. 假设递归调用成功,该函数有效。

您 运行 遇到了第二部分的问题;您增加了 k,但这并没有使您更接近 k < 10 的部分。简而言之,您可能想要切换该测试并确保您最初使用正确数量的参数调用该函数。 (Aadit M Shah 你用一个调用它,它期望两个,这意味着当你调用它时它最终是未定义的。)

无论如何,迭代在这里肯定会更好:

var n = 0;
for(var i = 0; i < 10; i++) {
    n = (5 * n + 1) % 8;
    console.log(n);
}

这里有两个略有不同的选项,具体取决于您希望达到的惯用程度和聪明程度。

经典的实现,由于 JS 不支持默认参数而稍作调整,将使用类似的东西:

var finalDepth = 0;
function slump(n, k) {
    k = k || 0; // Set to 0 if falsy (null, undef, or 0)
    if (logic) {
        finalDepth = k; // Record the depth on the last call
    } else {
        return slump((5*n + 1) % 8, k + 1);
    }
}

这将非常简单地记录最深的堆栈,并保留该值直到下一次调用。

如果你想稍微更像 JS,你可以使用闭包来跟踪调用:

function createGenerator() {
  var counter = 0;
  return {
    slump: function (n) {
      ++counter; // Closure captures counter, counter persists between slump calls but is unique for each createGenerator
      if (logic) {
        // stop
      } else {
        return slump((5*n + 1) % 8, k + 1);
      }
    },
    getCounter: function () { return counter; }
  }
}

您可以使用 ES6 iterators(或生成器)中的一些功能来使它更聪明。

函数参数 k 未初始化,因此不是数字。这特别意味着终止测试 k < 10 失败以及 k++ 语句不会更改 k 的值。所以 slump 总是用相同的参数值调用 k 并且递归永远不会停止。