在node.js中,全局变量的值在堆栈被无限递归超越后神秘地重置

Global variable value mysteriously reset after stack exceed by infinite-wannabe recursion in node.js

本文关键字:超越 递归 无限 js node 全局变量 堆栈      更新时间:2023-09-26

我想计算node.js (v0.4.10)中无限递归函数的步骤,使用全局值递增。然而,计数总是假装为零

> c = 0
> (function f() { c++; console.log(c); f() })();
1
2
...
18648
RangeError: Maximum call stack size exceeded
> c 
0

从函数内部将c值记录到控制台显示该值确实增加了,但在堆栈事故之后,它最终被重置。即使用global.c代替c

是正确的行为吗?这里发生了什么?例如,在铬(v14)中,c保持预期的最终计数。

更新

,结果证明上述内容仅在交互模式下有效。当从文件中执行代码时,在try-catch块中包含函数(防止过早退出),c值是正确的。

c = 0;
try {
  (function f() { c++; f() })();
} catch(e) {};
console.log(c);
然而,交互node.js和chromium javascript控制台之间仍然存在差异,其中值保留未处理的异常

每个交互模式的行为都与JavaScript文件的标准执行略有不同(Isaac Schlueter在某处写道:"我从未见过一个REPL没有至少一点魔法洒在上面")。交互模式必须对文本求值,这通常会在不同的上下文中运行代码。

在Node.JS的情况下,每个命令都在自己的上下文中执行,然后REPL会小心地将结果返回给我们。如果我们在命令中由于一些错误而失败,我们的变量值保持不变(因为更改的变量在执行的上下文中'死亡')。当我们以标准方式运行JavaScript文件时,我们没有这个单独的执行上下文,我们直接更改变量。

你可以改变你的例子,手动创建一个错误,并使用它:

c=0;
(function f(x){ c++; if(x) f(x-1); else throw new Error();  })(10);

只要代码执行错误,c的最终值在REPL中将为0。由于这个错误,REPL无法将c的全局值更新为在我们的测试函数的执行上下文中计算的值。