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

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

以上应该可以工作。

DEMO页面:https://jsfiddle.net/e7ooeq6m/

我在这篇文章中讨论了这种模式:

jQuery和$ questions

编辑:

如果查看ECMA脚本规范,可以使用3种方式定义函数。(第98页,第13节函数定义)

1. 使用函数构造函数

var sum = new Function('a','b', 'return a + b;');
alert(sum(10, 20)); //alerts 30

2. Using Function声明。

function sum(a, b)
{
    return a + b;
}

alert(sum(10, 10)); //Alerts 20;

3.函数表达式

var sum = function(a, b) { return a + b; }

alert(sum(5, 5)); // alerts 10

你可能会问,声明和表达式有什么区别?

来自ECMA脚本规范:

FunctionDeclaration: 函数标识符(FormalParameterListopt){函数体 } FunctionExpression: function Identifieropt (FormalParameterListopt){FunctionBody }

如果你注意到,'identifier'对于函数表达式是可选的。当你不给出标识符时,你创建了一个匿名函数。这并不意味着您不能指定标识符。

这意味着以下是有效的。

var sum = function mySum(a, b) { return a + b; }

需要注意的重要一点是,您只能在mySum函数体内部使用'mySum',而不能在函数体外部使用。请看下面的例子:

var test1 = function test2() { alert(typeof test2); }

alert(typeof(test2)); //alerts 'undefined', surprise! 

test1(); //alerts 'function' because test2 is a function.

现场演示

将其与

 function test1() { alert(typeof test1) };

 alert(typeof test1); //alerts 'function'

 test1(); //alerts 'function'

有了这些知识,让我们试着分析您的代码。

当你有这样的代码,

    function(msg) { alert(msg); }

您创建了一个函数表达式。你可以用圆括号来执行这个函数表达式。

    (function(msg) { alert(msg); })('SO'); //alerts SO.

其他回答

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

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

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

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

这也可以写成:

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

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

综上所述:

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

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

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

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

有一个很好的SO 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');

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

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

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

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

我感到困惑的一件事是“()”是分组操作符。

这是你声明的基本函数。

例1:

var message = 'SO';

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

foo(message);

函数是对象,可以分组。我们在函数周围加上括号。

例2:

var message = 'SO';

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

(foo)(message);     // calls foo

现在,我们不用声明并立即调用相同的函数,而是可以在调用时使用基本替换来声明它。

例3。

var message = 'SO';

(function foo(msg) {
    alert(msg);
})(message);          // declares & calls foo

最后,我们不需要额外的foo,因为我们没有使用名称来调用它!函数可以是匿名的。

例4。

var message = 'SO';

(function (msg) {   // remove unnecessary reference to foo
    alert(msg);
})(message);

要回答您的问题,请参考示例2。第一行声明了一些无名函数并对其进行分组,但不调用它。第二行对字符串进行分组。两者都不做任何事。(文森特的第一个例子。)

(function (msg){alert(msg)});  
('SO');                       // nothing.

(foo); 
(msg); //Still nothing.

But

(foo)
(msg); //works