Javascript 为什么需要在同一行上调用匿名函数?
我读了一些关于闭包的帖子,到处都能看到,但是没有明确的解释它是如何工作的——每次我被告知要使用它时…:Javascript 为什么需要在同一行上调用匿名函数?,javascript,anonymous-function,iife,Javascript,Anonymous Function,Iife,我读了一些关于闭包的帖子,到处都能看到,但是没有明确的解释它是如何工作的——每次我被告知要使用它时…: // 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 glo
// 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)})
然后将创建一个新的未命名函数,如函数“”(msg)
但是为什么这不起作用呢
(function (msg){alert(msg)});
('SO');
为什么它需要在同一条线上
你能给我指出一些帖子或给我一个解释吗?在函数定义后去掉分号
(function (msg){alert(msg)})
('SO');
上面的方法应该有效
演示页面:
我在这篇文章中讨论过这种模式:
编辑:
如果你看一下,有3种方法可以定义一个函数。(第98页,第13节功能定义)
1.使用函数构造函数
2.使用函数声明。
3.函数表达式
所以你可能会问,声明和表达式有什么区别
从ECMA脚本规范:
功能声明:
函数标识符(FormalParameterListopt){FunctionBody
}
函数表达式:
函数标识符opt(FormalParameterListopt){FunctionBody
}
如果您注意到,函数表达式的“标识符”是可选的。如果不提供标识符,则创建一个匿名函数。这并不意味着不能指定标识符
这意味着以下内容是有效的
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(){})
时所做的是返回一个函数对象。当您向其追加()
时,将调用它并执行正文中的任何内容。代码>表示语句结束,这就是第二次调用失败的原因。这就是JavaScript的工作方式。可以声明命名函数:
function foo(msg){
alert(msg);
}
var foo = function (msg) {
alert(msg);
}
function f(msg) {alert(msg)};
f('SO');
var foo = function(msg){
alert(msg);
}
并称之为:
foo("Hi!");
或者,您可以声明匿名函数:
function foo(msg){
alert(msg);
}
var foo = function (msg) {
alert(msg);
}
function f(msg) {alert(msg)};
f('SO');
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\u foo
的主体中用“var”定义的任何变量都将被make\u foo
返回的每个函数关闭,这是毫无意义的。这是一个闭包,它意味着一个函数对值所做的任何更改都将被另一个函数看到
这使您可以封装信息,如果需要:
function make_greeter(msg){
return function() { alert(msg) };
}
var hello = make_greeter("Hello!");
hello();
这就是除了Java之外几乎所有编程语言的工作方式。您展示的代码
(function (msg){alert(msg)});
('SO');
由两个语句组成。第一个是一个表达式,它生成一个函数对象(由于未保存,因此将对其进行垃圾收集)。第二个是生成字符串的表达式。要将函数应用于字符串,您需要在创建该字符串时将该字符串作为参数传递给函数(上面也显示了该参数),或者需要将函数实际存储在一个变量中,以便稍后在空闲时应用它。像这样:
var f = (function (msg){alert(msg)});
f('SO');
请注意,通过将匿名函数(lambda函数)存储在变量中,可以有效地为其命名。因此,您不妨定义一个常规函数:
function foo(msg){
alert(msg);
}
var foo = function (msg) {
alert(msg);
}
function f(msg) {alert(msg)};
f('SO');
var foo = function(msg){
alert(msg);
}
匿名函数不是名为“”的函数。它只是一个没有名字的函数
与JavaScript中的任何其他值一样,函数不需要创建名称。尽管将其与任何其他值一样绑定到一个名称上要有用得多
但与其他任何值一样,您有时希望使用它而不将其绑定到名称。这就是自调用模式
这是一个函数和一个数字,没有绑定,它们不起任何作用,永远不能使用:
function(){ alert("plop"); }
2;
因此,我们必须将它们存储在变量中才能使用它们,就像任何其他值一样:
var f = function(){ alert("plop"); }
var n = 2;
您还可以使用syntactic sugar将函数绑定到变量:
function f(){ alert("plop"); }
var n = 2;
但是,如果不需要命名它们,并且会导致更多的混乱和可读性降低,您可以立即使用它们
(function(){ alert("plop"); })(); // will display "plop"
alert(2 + 3); // will display 5
在这里,我的函数和数字没有绑定到变量,但它们仍然可以使用
这样说,看起来自调用函数没有实际价值。但您必须记住,JavaScript范围分隔符是函数,而不是块({})
<> P>因此,自调用函数实际上具有与C++、C或java块相同的含义。这意味着内部创建的变量不会“泄漏”到范围之外。为了不污染全局范围,这在JavaScript中非常有用。这个答案与这个问题没有严格的关系,但是您可能会感兴趣地发现这种语法特性并不是函数特有的。例如,我们总是可以这样做:
alert(
{foo: "I am foo", bar: "I am bar"}.foo
); // alerts "I am foo"
(function (msg){/*code here*/});('SO');
与功能相关。由于它们是从Function.prototype继承的对象,我们可以执行以下操作:
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"
};
有一件事让我感到困惑,“()”是分组运算符
这是您的基本声明函数
例1:
var message = 'SO';
function foo(msg) {
alert(msg);
}
foo(message);
函数是对象,可以分组。让我们围绕函数抛出paren
前。
function() {
alert("hello");
}();
(function() {
alert("hello");
})();
(function(){}) ('input') // Used in his example
(function(){}('input') )
var foo = function(msg){
alert(msg);
}
foo ('Few');
function(msg){
alert(msg);
} ('Few');
(function(msg){
alert(msg);
}) ('Few');
(function () {
return ( 10 + 20 );
})();
function help() {return true;}
(function (msg) { /* Code here */ });
('SO');
(function (msg){/*code here*/});('SO');
(function (msg){/*code here*/}) // This space is ignored by the interpreter
('SO');
(function (msg){alert(msg)});
('SO');
(function (msg){alert(msg)})
('SO');
(function (msg){alert(msg)})
('SO');
(function (msg){alert(msg)}('SO'));
void function (msg) { alert(msg); }
('SO');
var a = function (msg) { alert(msg); }
('SO');
!function (msg) { alert(msg); }
('SO');
var msg = "later dude";
window.onunload = function(msg){
alert( msg );
};
var myScript = (function() {
var pub = {};
//myscript.msg
pub.msg = "later dude";
window.onunload = function(msg) {
alert(msg);
};
//API
return pub;
}());