pal*_*lig 372 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 global object
window.onunload = function(){
// Which uses the 'hidden' variable
alert( msg );
};
// Close off the anonymous function and execute it
})();
Run Code Online (Sandbox Code Playgroud)
好的,我看到我们将创建新的匿名函数,然后执行它.所以在那之后这个简单的代码应该工作(并且确实如此):
(function (msg){alert(msg)})('SO');
Run Code Online (Sandbox Code Playgroud)
我的问题是这里发生了什么样的魔术?当我写作时我想:
(function (msg){alert(msg)})
Run Code Online (Sandbox Code Playgroud)
然后会创建一个新的未命名函数,如函数""(msg)...
但那么为什么这不起作用?
(function (msg){alert(msg)});
('SO');
Run Code Online (Sandbox Code Playgroud)
为什么它需要在同一行?
你能指点一些帖子或给我解释一下吗?
Sol*_*ogi 378
在函数定义后删除分号.
(function (msg){alert(msg)})
('SO');
Run Code Online (Sandbox Code Playgroud)
以上应该工作.
演示页面:https://jsfiddle.net/e7ooeq6m/
我在这篇文章中讨论了这种模式:
编辑:
如果查看ECMA脚本规范,可以使用3种方法定义函数.(第98页,第13节功能定义)
var sum = new Function('a','b', 'return a + b;');
alert(sum(10, 20)); //alerts 30
Run Code Online (Sandbox Code Playgroud)
function sum(a, b)
{
return a + b;
}
alert(sum(10, 10)); //Alerts 20;
Run Code Online (Sandbox Code Playgroud)
var sum = function(a, b) { return a + b; }
alert(sum(5, 5)); // alerts 10
Run Code Online (Sandbox Code Playgroud)
所以你可能会问,声明和表达之间有什么区别?
从ECMA脚本规范:
FunctionDeclaration:function Identifier(FormalParameterListopt){FunctionBody}
FunctionExpression:function Identifieropt(FormalParameterListopt){FunctionBody}
如果您注意到,'identifier' 对于函数表达式是可选的.当您不提供标识符时,您将创建一个匿名函数.这并不意味着您无法指定标识符.
这意味着以下有效.
var sum = function mySum(a, b) { return a + b; }
Run Code Online (Sandbox Code Playgroud)
需要注意的重要一点是,您只能在mySum函数体内使用"mySum",而不能在外部使用.请参阅以下示例:
var test1 = function test2() { alert(typeof test2); }
alert(typeof(test2)); //alerts 'undefined', surprise!
test1(); //alerts 'function' because test2 is a function.
Run Code Online (Sandbox Code Playgroud)
比较这个
function test1() { alert(typeof test1) };
alert(typeof test1); //alerts 'function'
test1(); //alerts 'function'
Run Code Online (Sandbox Code Playgroud)
有了这些知识,让我们试着分析你的代码.
当你有代码时,
function(msg) { alert(msg); }
Run Code Online (Sandbox Code Playgroud)
您创建了一个函数表达式.您可以通过将其包含在括号内来执行此函数表达式.
(function(msg) { alert(msg); })('SO'); //alerts SO.
Run Code Online (Sandbox Code Playgroud)
set*_*eth 128
它被称为自调用函数.
你在调用时正在做的(function(){})是返回一个函数对象.当你附加()到它时,它被调用并且正文中的任何东西都被执行.该;表示语句的结束,这就是为什么第二次调用失败.
Ben*_*min 93
我发现令人困惑的一件事是"()"是分组运算符.
这是您的基本声明功能.
防爆.1:
var message = 'SO';
function foo(msg) {
alert(msg);
}
foo(message);
Run Code Online (Sandbox Code Playgroud)
函数是对象,可以进行分组.所以让我们围绕这个功能抛出麻烦.
防爆.2:
var message = 'SO';
function foo(msg) { //declares foo
alert(msg);
}
(foo)(message); // calls foo
Run Code Online (Sandbox Code Playgroud)
现在我们可以使用基本替换来声明它,而不是声明和立即调用相同的函数.
防爆.3.
var message = 'SO';
(function foo(msg) {
alert(msg);
})(message); // declares & calls foo
Run Code Online (Sandbox Code Playgroud)
最后,我们不需要额外的foo,因为我们没有使用名称来调用它!功能可以是匿名的.
防爆.4.
var message = 'SO';
(function (msg) { // remove unnecessary reference to foo
alert(msg);
})(message);
Run Code Online (Sandbox Code Playgroud)
要回答您的问题,请参阅示例2.您的第一行声明了一些无名函数并对其进行分组,但不会调用它.第二行将字符串分组.两者都无所作为.(文森特的第一个例子.)
(function (msg){alert(msg)});
('SO'); // nothing.
(foo);
(msg); //Still nothing.
Run Code Online (Sandbox Code Playgroud)
但
(foo)
(msg); //works
Run Code Online (Sandbox Code Playgroud)
Vin*_*ert 23
匿名函数不是名为""的函数.它只是一个没有名字的功能.
与JavaScript中的任何其他值一样,函数不需要创建名称.虽然将其实际绑定到名称就像其他任何值一样有用得多.
但是,与任何其他值一样,您有时希望在不将其绑定到名称的情况下使用它.这是自我调用的模式.
这是一个函数和一个数字,没有绑定,它们什么也不做,永远不能使用:
function(){ alert("plop"); }
2;
Run Code Online (Sandbox Code Playgroud)
所以我们必须将它们存储在变量中以便能够使用它们,就像任何其他值一样:
var f = function(){ alert("plop"); }
var n = 2;
Run Code Online (Sandbox Code Playgroud)
您还可以使用syntatic sugar将函数绑定到变量:
function f(){ alert("plop"); }
var n = 2;
Run Code Online (Sandbox Code Playgroud)
但如果不需要命名它们会导致更多的混淆和更低的可读性,您可以立即使用它们.
(function(){ alert("plop"); })(); // will display "plop"
alert(2 + 3); // will display 5
Run Code Online (Sandbox Code Playgroud)
在这里,我的函数和我的数字没有绑定到变量,但它们仍然可以使用.
这样说,看起来自我调用功能没有实际价值.但是你必须记住JavaScript范围分隔符是函数而不是块({}).
因此,自调用函数实际上具有与C++,C#或Java块相同的含义.这意味着内部创建的变量不会在范围之外"泄漏".这在JavaScript中非常有用,以免污染全局范围.
jro*_*way 19
这就是JavaScript的工作原理.您可以声明一个命名函数:
function foo(msg){
alert(msg);
}
Run Code Online (Sandbox Code Playgroud)
并称之为:
foo("Hi!");
Run Code Online (Sandbox Code Playgroud)
或者,您可以声明一个匿名函数:
var foo = function (msg) {
alert(msg);
}
Run Code Online (Sandbox Code Playgroud)
并称之为:
foo("Hi!");
Run Code Online (Sandbox Code Playgroud)
或者,您永远不能将函数绑定到名称:
(function(msg){
alert(msg);
})("Hi!");
Run Code Online (Sandbox Code Playgroud)
函数也可以返回函数:
function make_foo() {
return function(msg){ alert(msg) };
}
(make_foo())("Hi!");
Run Code Online (Sandbox Code Playgroud)
在make_foo函数体中使用"var"定义的任何变量都将被返回的每个函数关闭,这一点毫无价值make_foo.这是一个闭包,它意味着一个函数对值的任何更改都将被另一个函数看到.
如果您愿意,这可以让您封装信息:
function make_greeter(msg){
return function() { alert(msg) };
}
var hello = make_greeter("Hello!");
hello();
Run Code Online (Sandbox Code Playgroud)
这几乎是几乎所有编程语言,但Java的工作原理.
你展示的代码,
(function (msg){alert(msg)});
('SO');
Run Code Online (Sandbox Code Playgroud)
由两个陈述组成.第一个是一个表达式,它产生一个函数对象(然后它将被垃圾收集,因为它没有被保存).第二个是产生字符串的表达式.要将函数应用于字符串,您需要在创建函数时将字符串作为参数传递给函数(您也在上面显示),或者您需要将函数实际存储在变量中,以便您可以在您的闲暇时间稍后申请.像这样:
var f = (function (msg){alert(msg)});
f('SO');
Run Code Online (Sandbox Code Playgroud)
请注意,通过在变量中存储匿名函数(lambda函数),您可以有效地为其命名.因此,你也可以定义一个常规函数:
function f(msg) {alert(msg)};
f('SO');
Run Code Online (Sandbox Code Playgroud)
总结以前的评论:
function() {
alert("hello");
}();
Run Code Online (Sandbox Code Playgroud)
未分配给变量时,会产生语法错误.代码被解析为函数语句(或定义),这使得右括号在语法上不正确.在函数部分周围添加括号告诉解释器(和程序员)这是一个函数表达式(或调用),如
(function() {
alert("hello");
})();
Run Code Online (Sandbox Code Playgroud)
这是一个自调用函数,这意味着它是匿名创建的并且立即运行,因为调用发生在声明它的同一行.这个自调用函数用熟悉的语法表示,用于调用无参数函数,并在函数名称周围添加括号:(myFunction)();.
我对提问者的问题的理解是这样的:
这个魔法是如何运作的:
(function(){}) ('input') // Used in his example
Run Code Online (Sandbox Code Playgroud)
我可能错了。然而,人们熟悉的通常做法是:
(function(){}('input') )
Run Code Online (Sandbox Code Playgroud)
原因是 JavaScript 括号 AKA()不能包含语句,并且当解析器遇到 function 关键字时,它知道将其解析为函数表达式而不是函数声明。
来源:博客文章立即调用函数表达式 (IIFE)
| 归档时间: |
|
| 查看次数: |
292793 次 |
| 最近记录: |