它不起作用,因为它被解析为a FunctionDeclaration
,并且函数声明的名称标识符是强制性的。
当用括号将其括起来时,它将被评估为FunctionExpression
,并且可以命名或不命名函数表达式。
a的语法FunctionDeclaration
如下:
function Identifier ( FormalParameterListopt ) { FunctionBody }
和FunctionExpression
s:
function Identifieropt ( FormalParameterListopt ) { FunctionBody }
如您所见,Identifier
(Identifier opt)令牌FunctionExpression
是可选的,因此我们可以使用没有定义名称的函数表达式:
(function () {
alert(2 + 2);
}());
或命名函数表达式:
(function foo() {
alert(2 + 2);
}());
括号(正式称为分组运算符)只能包围表达式,并且会评估函数表达式。
这两个语法产生可能会模棱两可,并且看起来可能完全相同,例如:
function foo () {} // FunctionDeclaration
0,function foo () {} // FunctionExpression
解析器知道它是a FunctionDeclaration
还是a FunctionExpression
,具体取决于它出现的上下文。
在上面的示例中,第二个是表达式,因为逗号运算符也只能处理表达式。
另一方面,FunctionDeclaration
s实际上只能出现在所谓的“ Program
”代码中,这意味着代码在全局范围之外以及在FunctionBody
其他函数的内部。
应该避免在块内部使用函数,因为它们可能导致不可预测的行为,例如:
if (true) {
function foo() {
alert('true');
}
} else {
function foo() {
alert('false!');
}
}
foo(); // true? false? why?
上面的代码实际上应该产生一个SyntaxError
,因为a Block
只能包含语句(并且ECMAScript规范未定义任何函数语句),但是大多数实现都是可以容忍的,并且将仅采用第二个函数,即alert的第二个函数'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;
};