之所以不起作用,是因为它被解析为FunctionDeclaration
,函数声明的名称标识符是强制性的。
当您使用括号括起来时,它将被视为FunctionExpression
进行评估,函数表达式可以有名称也可以没有。
FunctionDeclaration
的语法如下:
function Identifier ( FormalParameterListopt ) { FunctionBody }
还有 FunctionExpression
:
function Identifieropt ( FormalParameterListopt ) { FunctionBody }
如您所见,在FunctionExpression
中的 Identifier
(Identifieropt) 标记是可选的,因此我们可以定义一个没有名称的函数表达式:
(function () {
alert(2 + 2);
}());
< p > 或者 < em > 命名 函数表达式:
(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();
上述代码实际上应该产生一个 SyntaxError
,因为 Block
只能包含语句(而 ECMAScript 规范并未定义任何函数语句),但是大多数实现都很宽容,并将简单地采用第二个函数,即警报 'false!'
的那个。
Mozilla 实现——Rhino、SpiderMonkey——有不同的行为。它们的语法包含一个 非标准 函数声明,这意味着该函数将在运行时而不是解析时进行评估,就像使用 FunctionDeclaration
时发生的那样。在这些实现中,我们将得到定义的第一个函数。
函数可以用不同的方式声明,比较以下内容:
1- 使用 Function 构造函数定义的函数赋值给变量 multiply:
var multiply = new Function("x", "y", "return x * y;");
2- 名为 multiply 的函数声明:
function multiply(x, y) {
return x * y;
}
3- 一个分配给变量 multiply 的函数表达式:
var multiply = function (x, y) {
return x * y;
};
4- 一个命名的函数表达式 func_name,被赋值给变量 multiply:
var multiply = function func_name(x, y) {
return x * y;
};