【问题标题】:Javascript self calling anonymous function for scope closure [duplicate]用于范围关闭的Javascript自调用匿名函数[重复]
【发布时间】:2012-10-12 09:24:35
【问题描述】:

可能重复:
What advantages does using (function(window, document, undefined) { … })(window, document) confer?

我越来越多地在我一直使用的库中看到这样的代码:

(function (window) {
    var Foo = function () {
    }

    window.Foo = Foo;
})(window);

我看到这样做的理由是在创建(伪)类时避免在全局范围内工作。但是,如果我错了,请纠正我,我一直明白 window 是全局范围。我相信,当您创建一个全局变量时,您实际上只是向窗口添加了一个属性......除非这对于 ES5 strict 有所改变?

那么,基本上,有什么意义呢?我可以看到像这样组织的代码的唯一好处是,如果您想在以后通过传入除 window 之外的参数轻松更改类的命名空间。

【问题讨论】:

标签: javascript


【解决方案1】:

事实上,如果您忘记使用var 进行任何变量声明,严格模式 会引发异常。但是,即使不使用 外部封闭,它也可以工作。

使用这种模式更多地是为了保护自己免受外部 javascript 世界的影响。例如,一些其他脚本覆盖了 window.undefined 或任何其他变量,您可以获取该闭包中的值以便从内部访问它。

例如

(function _myApp( win, doc, undef ) {
    // app code
}( this, this.document ));

此外,当使用 var 声明变量或创建 函数声明 时,它们始终分别存储在当前 Activation Object 中>词汇环境记录。这意味着,不使用 Function context,您可以轻松地从其他点覆盖方法和变量,因为所有这些都将存储在当前 Context 中(这将是全球性的)

所以:

(function _myApp( win, doc, undef ) {
    var myVar = 42;

    function myFunc() {
    }
}( this, this.document ));

(function _myModule( win, doc, undef ) {
    var myVar = 42;

    function myFunc() {
    }
}( this, this.document ));

这是因为 closureContext 起作用的,但是如果您使用相同的代码,没有 Function Context,我们显然会覆盖我们的myVarmyFunc。这可能发生在任何地方,在同一个文件中或在另一个加载的脚本中。

【讨论】:

  • 是的,我很高兴看到这个例外。但是,仅从没有外部闭包的 var 以这种方式声明全局似乎没有作用域优势。安全性优势很有趣,性能和最小化改进也很有趣。
  • @blask:有趣的是,我前段时间专门针对window 对象对访问进行了基准测试,结果,访问 cached 引用总是比直接访问更快window。仅依靠浏览器范围链查找将获得最差的性能,例如,仅调用 setTimeout
【解决方案2】:

与全局变量一样邪恶,您至少需要一个,否则无法访问您的脚本。您提供的代码是创建该全局变量的一种方法。我更喜欢这种方式:

window.Foo = (function () {
    var func = function () {
        //  ...
    };

    return {
        func: func
    };
})();

【讨论】:

  • Douglas Crockford 的方法从这里开始:stackoverflow.com/questions/5020479/… 我倾向于编写 js 的方式无论如何我只会为我的类创建全局变量。因此,似乎没有必要拥有额外的范围功能。不过,缩小和性能优势很有趣
  • @blask 额外的作用域是实现公共和私有方法的唯一方法,它不是不必要的。这种特殊的模式称为revealing module IIFE
  • 是的,我也这样做了一个额外的闭包,对不起,我专门指的是以原始帖子的方式传递窗口对象
【解决方案3】:

你是对的,但不同之处在于函数内部的代码就像一个自动 init 函数。

(function (window) {
    var Foo = function () {
    }

    var Bar = 69; // not in global scope

    window.Foo = Foo; // in global scope
})(window);

相对

var Foo = function () { // in global scope
}

var Bar = 69; // in global scope

var Foo = function () { // in global scope
}

function init () {
    var Bar = 69; // not in global scope
}
init();

【讨论】:

  • 仍然不需要传入window作为参数。您可以使用返回要分配的对象的 IIFE 来实现相同的效果。请参阅 jbaby 的回答。
  • 这是使用自调用匿名函数的好处,但与范围问题无关
猜你喜欢
  • 1970-01-01
  • 2013-06-25
  • 2012-02-23
  • 2011-02-13
  • 2013-08-29
  • 2013-04-16
  • 1970-01-01
  • 1970-01-01
  • 2012-06-05
相关资源
最近更新 更多