您能解释JavaScript中封装的匿名函数的语法背后的缘由吗? 为何这样作: (function(){})();
但这不是: function(){}();
? express
在JavaScript中,将建立一个命名函数,以下所示: ide
function twoPlusTwo(){ alert(2 + 2); } twoPlusTwo();
您还能够建立一个匿名函数并将其分配给变量: 模块化
var twoPlusTwo = function(){ alert(2 + 2); }; twoPlusTwo();
您能够经过建立一个匿名函数来封装代码块,而后将其包装在方括号中并当即执行: 函数
(function(){ alert(2 + 2); })();
在建立模块化脚本时,这颇有用,以免因潜在冲突的变量而使当前范围或全局范围混乱(例如Greasemonkey脚本,jQuery插件等)。 lua
如今,我明白了为何这样作了。 方括号将内容括起来,仅显示结果(我敢确定有一种更好的描述方式),例如(2 + 2) === 4
。 spa
可是我不明白为何这不能一样有效: 插件
function(){ alert(2 + 2); }();
你能跟我解释一下吗? 调试
即便这是一个古老的问答,它仍然讨论了一个主题,该主题至今仍使许多开发人员陷入困境。 我没法计算我采访过的JavaScript开发人员候选人的人数,这些候选人没法告诉我函数声明和函数表达式之间的区别, 而且谁也不知道当即调用的函数表达式是什么。 code
不过,我想提一件事,很是重要的一点是,即便Premasagar给出了名称标识符,它的代码段也没法使用。 orm
function someName() { alert(2 + 2); }();
之因此不起做用,是由于JavaScript引擎将其解释为函数声明,而后是一个彻底不相关的不包含表达式的分组运算符,而且分组运算符必须包含一个表达式。 根据JavaScript,以上代码片断等同于如下代码片断。
function someName() { alert(2 + 2); } ();
我想指出的另外一件事多是对某些人有用:您为函数表达式提供的任何名称标识符在代码的上下文中几乎没有用,除非是在函数定义自己内部。
var a = function b() { // do something }; a(); // works b(); // doesn't work var c = function d() { window.setTimeout(d, 1000); // works };
固然,在调试代码时,将名称标识符与函数定义一块儿使用老是颇有帮助的,但这彻底是另外一回事... :-)
它不起做用是由于它被解析为FunctionDeclaration
,而且函数声明的名称标识符是强制性的 。
当用括号将其括起来时,它将被视为FunctionExpression
,而且能够命名或不命名函数表达式。
FunctionDeclaration
的语法以下所示:
function Identifier ( FormalParameterListopt ) { FunctionBody }
和FunctionExpression
s:
function Identifieropt ( FormalParameterListopt ) { FunctionBody }
如您所见, FunctionExpression
的Identifier
(Identifier opt )标记是可选的,所以咱们可使用一个未定义名称的函数表达式:
(function () { alert(2 + 2); }());
或命名函数表达式:
(function foo() { alert(2 + 2); }());
括号(正式称为分组运算符 )只能包围表达式,而且会对函数表达式求值。
这两个语法产生可能会模棱两可,而且看起来可能彻底相同,例如:
function foo () {} // FunctionDeclaration 0,function foo () {} // FunctionExpression
解析器知道它是FunctionDeclaration
仍是FunctionExpression
,具体取决于它出现的上下文 。
在上面的示例中,第二个是表达式,由于逗号运算符也只能处理表达式。
另外一方面, FunctionDeclaration
实际上只能出如今所谓的“ Program
”代码中,意味着在全局范围以外以及在其余函数的FunctionBody
内部。
应该避免在块内部使用函数,由于它们可能致使不可预测的行为,例如:
if (true) { function foo() { alert('true'); } } else { function foo() { alert('false!'); } } foo(); // true? false? why?
上面的代码实际上应该产生一个SyntaxError
,由于一个Block
只能包含语句(而且ECMAScript规范没有定义任何函数语句),可是大多数实现是能够容忍的,而且将仅采用第二个函数,该函数会警告'false!'
。
Mozilla实现-Rhino,SpiderMonkey-具备不一样的行为。 它们的语法包含一个非标准的 Function语句,这意味着该函数将在运行时而不是在解析时进行评估,这与FunctionDeclaration
s同样。 在这些实现中,咱们将定义第一个函数。
能够用不一样的方式声明函数,请比较如下内容 :
1-一个函数,该函数使用分配给变量的Function构造函数 乘法 :
var multiply = new Function("x", "y", "return x * y;");
2-名为乘法的函数的函数声明:
function multiply(x, y) { return x * y; }
3-分配给变量multipli的函数表达式:
var multiply = function (x, y) { return x * y; };
4-命名函数表达式func_name ,分配给变量multipli :
var multiply = function func_name(x, y) { return x * y; };
也许简短的答案是
function() { alert( 2 + 2 ); }
是定义 (匿名)函数的函数文字 。 附加的()对,被解释为一个表达式,不但愿在顶层使用,仅在文字上使用。
(function() { alert( 2 + 2 ); })();
在调用匿名函数的表达式语句中。
(function(){ alert(2 + 2); })();
上面是有效的语法,由于括号内传递的任何内容都被视为函数表达式。
function(){ alert(2 + 2); }();
上面的语法无效。 由于Java脚本语法分析器在function关键字以后查找功能名称,由于它找不到任何东西,所以会引起错误。
好的答案已经发布。 但我想指出,函数声明返回一个空的完成记录:
FunctionDeclaration :
function
BindingIdentifier(
FormalParameters)
{
FunctionBody}
- 返回NormalCompletion (空)。
这个事实不容易观察,由于大多数尝试获取返回值的方法都会将函数声明转换为函数表达式。 可是, eval
显示:
var r = eval("function f(){}"); console.log(r); // undefined
调用空的完成记录没有任何意义。 这就是为何function f(){}()
没法工做。 实际上,JS引擎甚至没有尝试调用它,括号被视为另外一条语句的一部分。
可是,若是将函数包装在括号中,它将变成函数表达式:
var r = eval("(function f(){})"); console.log(r); // function f(){}
函数表达式返回一个函数对象。 所以,您能够将其称为: (function f(){})()
。