15

在我的顶级函数中,我使用 require.js 导入了一些依赖项。他们在那里,没问题。在这个函数中,我定义了一个回调函数,并尝试使用一些通过 require.js 导入的变量,即父闭包中的变量。

他们只是不存在,正如断点和浏览 Chrome 检查器的范围变量面板所证实的那样。

我知道fn.apply朋友们只是尽可能this地设置上下文,而不是他们可以破坏对闭包的引用或改变范围链。

define([
    'backbone',
    'backbone.vent',
    'app/utils/foo',
    'app/services/intent'
], function(Backbone, Vent, Foo) {
    'use strict';

    // Backbone, Vent, and Foo are defined here

    Vent.on('myevent', function(options) {
        // Backbone is defined here, but not Vent or Foo.
    });
});

这怎么可能?

我该如何解决?

4

2 回答 2

30

我怀疑您设置断点的函数包含对 的引用Backbone,但不包含Ventor Foo

闭包在 JS 运行时有点昂贵。它要求引擎以这样一种方式包装对象,即它保留对这些变量的内部引用,以便在执行函数时可以正确解析它们。因此,出于性能原因,Chrome(我怀疑大多数其他引擎也是如此)倾向于优化掉编译脚本时实际未使用的任何闭包变量。这可能会在调试时导致一些令人困惑的事情,但这是可以预料的。

考虑以下示例(注意xyz是在外部函数的范围内定义的,而不是在全局范围内):

window.onload = function() {
  var x = 1, y = 2, z = 3;
  (function() {
    debugger;
    x++;
  })();
}

备用 JSFiddle 演示

如果您在此脚本命中指令时尝试在控制台上输出x和输出,您将看到以下内容:ydebugger

控制台输出

如果您查看Scope Variable面板,您会看到:

范围变量

为什么?因为 Chrome 已经确定y并且z没有在函数中使用,所以编译后的代码不需要保留对变量的引用。如果您y在脚本中添加对的引用,那么编译器将保留对它的引用,并且该名称将不再出现undefined在调试器中。

于 2014-02-20T19:48:50.187 回答
3

如果您在闭包中使用 eval(),Chrome 将不会使用它的任何性能优化,这意味着您可以看到 y 的值

于 2014-05-17T00:56:09.477 回答