拨开荷叶行,寻梦已然成。仙女莲花里,翩翩白鹭情。
IMG-LOGO
主页 文章列表 javascript/nodeJs中的两个递回函式和stackoverflow错误。了解差异

javascript/nodeJs中的两个递回函式和stackoverflow错误。了解差异

白鹭 - 2022-03-25 2118 0 0

查看 SICP 书和 JS 函式式编程,我创建了两个递回函式。我的期望是它们都引发了堆栈溢位错误。但只有 sumAll() 函式引发了错误。请参阅下面两个函式 sumAll() 和 factorial() 的代码:

正如预期的那样, sumAll() 函式确实引发了堆栈溢位错误

function sumAll(n, i = 0, result = 0) {
  return (i > n)
    ? result
    : sumAll(n, i   1, i   result);
}
    
console.log(sumAll(10000));

下面的 factorial() 函式没有引发堆栈溢位错误:

function factorial(n){
  return (n == 1)
    ? 1
    :  n* factorial((n-1))
}
    
console.log(factorial(10000))

我的问题是为什么 factorial() 函式不会引发堆栈溢位并且在 nodeJS 中完美运行,同时 sumAll() 确实在 nodeJS 中也引发了它

uj5u.com热心网友回复:

您的第一个函式能够利用尾呼叫优化,而您的第二个函式不是(或者它是,但可能不是以 node.js 语言实作的方式)。

考虑一下:你的第一个函式的通常条件是它以 结尾return sumAll(n, i 1, i result),这意味着一旦你得到一些要回传的东西,你就可以回传它。

但是return n* factorial((n-1))您的第二个函式以 结尾,这意味着一旦您要回传某些内容,就必须对其进行 ANOTHER 操作(将其乘以 n),然后才能实际回传结果。

我相信 node.js 解释器无法对第二个函式进行尾呼叫优化,因为它需要在回传之前对其执行另一个操作。

请注意:我不确定这是不是答案,并且我怀疑 node.js 可能不支持任何型别的尾呼叫优化。这是我的理论,但为什么一个函式可能会以这种方式出错而另一个函式不会。

uj5u.com热心网友回复:

在呼叫堆栈大小中也考虑了区域变量的数量(即区域变量的存储器)。

function computeMaxCallStackFrames(a, b, c, d) {
  try {
    return 1   computeMaxCallStackFrames(a   1, b   1, c   2, d   3);
  } catch (e) {
    // Call stack overflow
    // console.log(e);
    return 1;
  }
}
var stackFrames = computeMaxCallStackFrames(1, 4, 6, 2);
console.log(stackFrames);

尝试增加编号。的自变量,你会看到递回呼叫/呼叫堆栈帧的数量减少。

function computeMaxCallStackFrames(a, b, c, d, e) {
  try {
    return 1   computeMaxCallStackFrames(a   1, b   1, c   2, d   3, e-2);
  } catch (e) {
    // Call stack overflow
    // console.log(e);
    return 1;
  }
}
var stackFrames = computeMaxCallStackFrames(1, 4, 6, 2, 9);
console.log(stackFrames);

零区域变量。

function computeMaxCallStackFrames() {
  try {
    return 1   computeMaxCallStackFrames();
  } catch (e) {
    // Call stack overflow
    // console.log(e);
    return 1;
  }
}
var stackFrames = computeMaxCallStackFrames();
console.log(stackFrames);

因此,我们可以清楚地看到,在呼叫堆栈大小中也考虑了区域变量的数量(即区域变量的存储器)。如果有很多区域变量,那么没有。递回呼叫的次数会更少。

编辑:我们都知道堆栈大小会因浏览器而异。所以输出在不同的浏览器中不会相同,但在同一个浏览器中应该是一致的,即使我们多次运行它。

希望现在一切都说得通。

标签:

0 评论

发表评论

您的电子邮件地址不会被公开。 必填的字段已做标记 *