我读了一些关于闭包的帖子,到处都看到了这个,但是没有明确的解释它是如何工作的——每次我都被告知要使用它…:

// Create a new anonymous function, to use as a wrapper
(function(){
    // The variable that would, normally, be global
    var msg = "Thanks for visiting!";

    // Binding a new function to a global object
    window.onunload = function(){
        // Which uses the 'hidden' variable
        alert( msg );
    };
// Close off the anonymous function and execute it
})();

好的,我看到我们将创建一个新的匿名函数,然后执行它。所以在这之后,这段简单的代码应该工作了(它确实工作了):

(function (msg){alert(msg)})('SO');

我的问题是这里发生了什么魔法?当我写到:

(function (msg){alert(msg)})

然后将创建一个新的未命名函数,如function ""(msg)…

但为什么这行不通呢?

(function (msg){alert(msg)});
('SO');

为什么要在同一条线上?

你能给我指出一些帖子或者给我一个解释吗?


当前回答

它是一个自动执行的匿名函数。第一组括号包含要执行的表达式,第二组括号执行这些表达式。

(function () {
    return ( 10 + 20 );
})();

Peter Michaux在《一对重要的圆括号》中讨论了两者的区别。

当试图从父名称空间隐藏变量时,它是一个有用的构造。函数中的所有代码都包含在函数的私有作用域中,这意味着它根本不能从函数外部访问,这使得它真正是私有的。

See:

闭合(计算机科学) JavaScript命名空间 Javascript中重要的一对括号

其他回答

不带括号的例子:

void function (msg) { alert(msg); }
('SO');

(这是void的唯一真正用途,afaik)

or

var a = function (msg) { alert(msg); }
('SO');

or

!function (msg) { alert(msg); }
('SO');

同时也要工作。void导致表达式求值,以及赋值和bang。最后一个可以使用~、+、-、delete、typeof和一些一元操作符(void也是其中之一)。不工作的当然是++,——因为有一个变量的要求。

换行符是不必要的。

(function (msg){alert(msg)})
('SO');

这是一种使用匿名函数作为闭包的常见方法,许多JavaScript框架都使用这种方法。

编译代码时自动调用此函数。

如果放置;在第一行,编译器将其视为两个不同的行。所以你不能得到和上面一样的结果。

这也可以写成:

(function (msg){alert(msg)}('SO'));

要了解更多细节,请参阅JavaScript/匿名函数。

IIFE简单地划分了函数并隐藏了msg变量,以便不“污染”全局名称空间。事实上,只要保持简单,就像下面这样做,除非你正在建立一个十亿美元的网站。

var msg = "later dude";
window.onunload = function(msg){
  alert( msg );
};

你可以使用一个显示模块模式来命名你的msg属性,比如:

var myScript = (function() {
    var pub = {};
    //myscript.msg
    pub.msg = "later dude";
    window.onunload = function(msg) {
        alert(msg);
    };
    //API
    return pub;
}());

JavaScript函数还有一个属性。如果你想递归调用同一个匿名函数。

(function forInternalOnly(){

  //you can use forInternalOnly to call this anonymous function
  /// forInternalOnly can be used inside function only, like
  var result = forInternalOnly();
})();

//this will not work
forInternalOnly();// no such a method exist

这就是JavaScript的工作原理。你可以声明一个命名函数:

function foo(msg){
   alert(msg);
}

叫它:

foo("Hi!");

或者,你可以声明一个匿名函数:

var foo = function (msg) {
    alert(msg);
}

称之为:

foo("Hi!");

或者,你可以永远不将函数绑定到一个名称:

(function(msg){
   alert(msg);
 })("Hi!");

函数也可以返回函数:

function make_foo() {
    return function(msg){ alert(msg) };
}

(make_foo())("Hi!");

make_foo函数体中任何用“var”定义的变量都将被make_foo返回的每个函数关闭,这是毫无意义的。这是一个闭包,这意味着一个函数对值所做的任何更改都将被另一个函数可见。

这让你可以封装信息,如果你想:

function make_greeter(msg){
    return function() { alert(msg) };
}

var hello = make_greeter("Hello!");

hello();

除了Java,几乎所有编程语言都是这样工作的。