6

脚步:

  1. 在 Firefox 29.0.1 (Windows 7 x64) 中打开页面:

    <!doctype html>
    <title>Test</title>
    <script>
        (function () {
            var x = 5, f = function () {
                setTimeout(f, 1000);
            };
            f();
        }());
    </script>
    
  2. 打开开发人员工具 ( F12)。

  3. Debugger中,设置断点:setTimeout(f, 1000);

  4. 一旦断点被​​命中,x在控制台中进行评估。结果:undefined

    显示何时评估 <code>x</code> 的屏幕截图

  5. 重新加载页面。断点在第一次运行时命中f

  6. 评估x。结果:5

  7. 继续执行,当再次命中断点时,评估x. 结果相同:5

我的假设:如果 Firefox 在第一次运行时意识到f不需要x,那么它就不会存储x"with"的值f。所以在随后调用isf的值时。有趣的是,我在 Chrome 35 和 IE11 中看到了相同的行为。xundefined

问题: 发生了什么事?我可以将 Firefox 配置为x在第 4 步(见上文)中评估其正确值吗?

4

1 回答 1

6

看来你的假设是正确的。问题是当调试器未运行时,变量已被优化或删除。当您在调试器运行的情况下刷新页面时,它允许您访问函数的内部范围,以便您可以更轻松地调试代码。

如果那里没有断点,这是不可能的,所以必须禁用 JIT 编译器才能让你这样做。垃圾收集器还注意到这些仍然可以在范围内引用,因此不会删除这些变量。

如果 JIT 编译器正在运行,它将识别出该x变量未在任何地方使用,并将其从生成的代码中删除。如果 JIT 编译器没有运行,垃圾收集 (GC) 将在 GC 循环运行时删除该变量,因为没有引用该变量。

因为它无法撤消已经完成的操作,所以当您第一次遇到断点时它是未定义的。

即使禁用 JIT 编译器,也无法真正防止这种情况发生。虽然从技术上讲,您可以将垃圾收集限制设置得非常高以尝试阻止它这样做,甚至删除垃圾收集代码并重建 Firefox,但这是非常愚蠢的——您最终只会泄漏一堆内存,那就是比简单地刷新页面要麻烦得多。

有趣的是,如果您尝试做同样的事情,Firefox 31 (Aurora) 会提供更具描述性的错误消息:

Error: variable has been optimized out
于 2014-06-06T09:51:32.620 回答