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

// 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');

为什么要在同一条线上?

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


当前回答

匿名函数不是名称为“”的函数。它只是一个没有名字的函数。

与JavaScript中的其他值一样,函数不需要创建名称。不过,像绑定其他值一样,将它实际绑定到名称上要有用得多。

但是像任何其他值一样,您有时希望使用它时不将其绑定到名称。这就是自我调用模式。

这是一个函数和一个数字,没有界限,它们什么都不做,永远不能被使用:

function(){ alert("plop"); }
2;

所以我们必须将它们存储在一个变量中才能使用它们,就像任何其他值一样:

var f = function(){ alert("plop"); }
var n = 2;

你也可以使用synatic sugar将函数绑定到一个变量:

function f(){ alert("plop"); }
var n = 2;

但是如果不需要命名它们,并且会导致更多的混乱和更低的可读性,那么您可以立即使用它们。

(function(){ alert("plop"); })(); // will display "plop"
alert(2 + 3); // will display 5

在这里,我的函数和数字没有绑定到一个变量,但它们仍然可以使用。

这样说,看起来自调用函数没有真正的价值。但您必须记住,JavaScript范围分隔符是函数而不是块({})。

因此,自调用函数实际上与c++、c#或Java块具有相同的含义。这意味着在内部创建的变量不会“泄漏”到作用域之外。为了不污染全局作用域,这在JavaScript中非常有用。

其他回答

另一个观点

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

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');

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

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

它会起作用的。

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

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

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

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

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

See:

闭合(计算机科学) JavaScript命名空间 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;
}());

我对提问者问题的理解是:

这个魔法是如何起作用的:

(function(){}) ('input')   // Used in his example

我可能错了。然而,人们熟悉的通常做法是:

(function(){}('input') )

原因是JavaScript括号AKA()不能包含语句,当解析器遇到function关键字时,它知道将其解析为函数表达式而不是函数声明。

来源:博客文章立即调用函数表达式(IIFE)