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

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

为什么要在同一条线上?

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


当前回答

不带括号的例子:

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/匿名函数。

综上所述:

function() {
  alert("hello");
}();

当未赋值给变量时,将产生语法错误。代码被解析为函数语句(或定义),这使得闭括号在语法上不正确。在函数部分周围添加圆括号告诉解释器(和程序员)这是一个函数表达式(或调用),如

(function() {
  alert("hello");
})();

这是一个自调用函数,这意味着它是匿名创建的并立即运行,因为调用发生在声明它的同一行中。这个自调用函数使用熟悉的语法指示为调用无参数函数,在函数名周围加上括号:(myFunction)();。

有一个很好的SO JavaScript函数语法讨论。

这个答案与问题没有严格的联系,但是您可能有兴趣发现这种语法特性并不是函数特有的。例如,我们总是可以这样做:

alert(
    {foo: "I am foo", bar: "I am bar"}.foo
); // alerts "I am foo"

与函数相关。因为它们是继承自Function的对象。原型,我们可以这样做:

Function.prototype.foo = function () {
    return function () {
        alert("foo");
    };
};

var bar = (function () {}).foo();

bar(); // alerts foo

你知道,我们甚至不需要用圆括号来包围函数来执行它们。不管怎样,只要我们试着把结果赋值给一个变量。

var x = function () {} (); // this function is executed but does nothing

function () {} (); // syntax error

对于函数,一旦声明了它们,就可以对它们调用new操作符并获得一个对象。以下是等价的:

var obj = new function () {
    this.foo = "bar";
};

var obj = {
    foo : "bar"
};

它被称为自调用函数。

当你调用(function(){})时,你所做的是返回一个函数对象。当您将()追加到它时,它将被调用,并执行主体中的任何内容。的;表示语句的结束,这就是第二次调用失败的原因。

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

与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中非常有用。