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

// 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 (msg){alert(msg)});
('SO');

由两个语句组成。第一个是一个产生函数对象的表达式(由于没有保存,该函数对象随后将被垃圾收集)。第二个是一个产生字符串的表达式。要将函数应用到字符串,您要么需要在创建函数时将字符串作为参数传递给函数(上面也显示了这一点),要么需要实际将函数存储在变量中,以便稍后在空闲时应用它。像这样:

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

注意,通过在变量中存储匿名函数(lambda函数),您实际上是在给它一个名称。因此你也可以定义一个普通的函数:

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

其他回答

当你这样做的时候:

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

由于分号的原因,您在('SO')之前结束了函数。如果你这样写:

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

它会起作用的。

工作示例:http://jsfiddle.net/oliverni/dbVjg/

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;
}());

另一个观点

首先,你可以声明一个匿名函数:

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

然后你称之为:

foo ('Few');

因为foo = function(msg){alert(msg);}所以你可以将foo替换为:

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

但是您应该将整个匿名函数包装在一对大括号中,以避免在解析时声明函数时出现语法错误。然后我们有,

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

这样,我就很容易理解了。

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

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

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

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

这也可以写成:

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

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

它不起作用的简单原因不是因为;表示匿名函数结束。这是因为在函数调用的末尾没有(),它就不是函数调用。也就是说,

function help() {return true;}

如果调用result = help();这是对函数的调用,返回true。

如果你拨打result = help;这不是电话。在这种分配中,帮助被视为要分配给结果的数据。

你所做的是通过添加分号来声明/实例化一个匿名函数,

(function (msg) { /* Code here */ });

然后尝试在另一个语句中调用它,只使用括号…显然,因为函数没有名称,但这将不起作用:

('SO');

解释器将第二行上的括号视为一个新的指令/语句,因此它不起作用,即使你这样做:

(function (msg){/*code here*/});('SO');

它仍然不能工作,但当您删除分号时,它可以工作,因为解释器会忽略空白和空格,并将完整的代码视为一条语句。

(function (msg){/*code here*/})        // This space is ignored by the interpreter
('SO');

Conclusion: a function call is not a function call without the () on the end unless under specific conditions such as being invoked by another function, that is, onload='help' would execute the help function even though the parentheses were not included. I believe setTimeout and setInterval also allow this type of function call too, and I also believe that the interpreter adds the parentheses behind the scenes anyhow which brings us back to "a function call is not a function call without the parentheses".