为何须要在同一行上调用匿名函数?

我读了一些有关闭包的文章,处处都看到了,可是没有明确的解释它是如何工做的-每当我被告知要使用它时……: 编程

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

个人问题是这里发生了什么魔术? 我觉得当我写: app

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

而后将建立一个新的未命名函数,如函数“”(msg)... 编程语言

可是,为何这不起做用? ide

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

为何它须要在同一行? 函数

您能给我指出一些帖子仍是给我一个解释? spa


#1楼

将分号放在函数定义以后。 .net

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

以上应该工做。 code

演示页面: https : //jsfiddle.net/e7ooeq6m/ orm

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

jQuery和$问题

编辑:

若是您查看ECMA脚本规范 ,则能够经过3种方式定义函数。 (第98页,第13节“功能定义”)

1.使用函数构造函数

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

2.使用函数声明。

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){FunctionBody}

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.

#2楼

这称为自调用函数。

调用(function(){})时,您正在作的事情是返回一个函数对象。 当您将()附加到它时,将调用它,而且执行体内的任何内容。 的; 表示语句的结尾,这就是第二次调用失败的缘由。


#3楼

这就是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返回的每一个函数都将关闭在make_foo主体中用“ var”定义的任何变量,这make_foo 。 这是一个闭包,这意味着一个函数对值所作的任何更改将对另外一个函数可见。

若是须要,这使您能够封装信息:

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

var hello = make_greeter("Hello!");

hello();

这几乎是除Java以外的每种编程语言的工做方式。


#4楼

您显示的代码,

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

两个语句组成。 第一个是产生函数对象的表达式(因为未保存,所以将对其进行垃圾回收)。 第二个是产生字符串的表达式。 要将函数应用于字符串,您须要在建立函数时将字符串做为参数传递给函数(也在上面显示),或者须要将函数实际存储在变量中,以便您能够在之后的空闲时间应用它。 像这样:

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

请注意,经过在变量中存储匿名函数(lambda函数),能够有效地为其命名。 所以,您也能够定义一个常规函数:

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

#5楼

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

像JavaScript中的任何其余值同样,函数不须要建立名称。 尽管实际上将其绑定到名称就像其余任何值同样有用。

可是,像其余任何值同样,有时您但愿使用它而不将其绑定到名称。 这就是自我调用模式。

这是一个函数和一个数字,不受限制,它们什么也不作,永远不能使用:

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

所以,咱们必须将它们存储在变量中才能使用它们,就像其余任何值同样:

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

您还可使用语法糖将函数绑定到变量:

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

可是,若是不须要命名它们,而且会致使更多的混乱和可读性下降,则能够当即使用它们。

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

在这里,个人函数和个人数字未绑定到变量,但仍可使用。

这样说,看起来自调用功能没有实际价值。 可是您必须记住,JavaScript做用域分隔符是函数而不是块({})。

所以,自调用函数实际上与C ++,C#或Java块具备相同的含义。 这意味着在内部建立的变量不会在范围外“泄漏”。 这在JavaScript中很是有用,以避免污染全局范围。

相关文章
相关标签/搜索