如何用递归函数替换while?

ale*_*lex 3 javascript recursion while-loop

while以这种方式使用:

while (value < -180 || value > 180) {
  if (value < -180) {
    value += 360
  }
  if (value > 180) {
    value -= 360
  }
}
Run Code Online (Sandbox Code Playgroud)

不过,我想使用递归函数而不是while. 我在谷歌上搜索但找不到任何东西。所以我想也许我可以在这里得到答案。

Car*_*ate 5

将显式循环转换为递归解决方案的“通用公式”是:

  • 找出循环的“累加器”是什么。通常,循环将操作一个或两个值,这些值是循环的“结果”。

  • 将累加器作为函数的参数。

很难概括如何用递归替换任何旧循环,但这可以用作一般准则:

对于具有以下形式的循环:

var a, b, c = ...;

while (condition) {
   // Change a, b, c...
}

// Use a, b, c
Run Code Online (Sandbox Code Playgroud)

您可以将其转换为:

function recursive(a, b, c...) {
   // When the condition does *not* hold, end the recursion.
   // Note that condition is negated relative to the while-loop.
   if (!condition) {
      // Base case.
      return [a, b, c...];

   } else {
      // Change a, b, c...
      //  and recurse with the new values
      return recursive(a', b', c'...);
   }
}
Run Code Online (Sandbox Code Playgroud)

对于您的示例,这看起来像:

function recur(value) {
  if (value > -180 || value < 180) {
    return value; // Base case

  } else if (value < -180) {
    return recur(value + 360);

  } else {
    return recur(value - 360);
  }
}
Run Code Online (Sandbox Code Playgroud)

如果您希望再次循环,请递归,但请记住您需要返回递归的结果。对于想要结束循环的情况,返回累加器。请注意,每个执行分支都必须以 return 结束。一旦您丢弃递归结果(通过不返回它),数据就会丢失。

但请注意:

  • 正如我在评论中提到的,递归并不是一个可以用来解决任何老问题的锤子;它应该是一个解决问题的工具。特别是当语言没有针对它进行优化时。对于小问题来说这可能没问题,但是当问题变得更大时,你可能会发现它会突然开始导致 StackOverflows。

  • 在处理可变数据时,递归可能会变得困难且令人困惑。如果您的累加器是可变的(列表、映射或任何其他非基元),则您必须非常小心地设置所有内容。可以从递归的每个分支访问和更改相同的数据。如果你不小心,你的累加器就会以非常难以调试的方式被改变。如果您想走递归/函数式路径,我鼓励您研究像 Immutable.js 这样的库,或者像 Clojurescript 这样几乎专门处理不可变结构的语言。Clojurescript 编译成 JavaScript。