Он не работает, потому что он анализируется как a FunctionDeclaration
, и идентификатор имени объявления функции является обязательным .
Когда вы заключаете его в скобки, оно оценивается как a FunctionExpression
, а выражения функций могут быть именованы или нет.
Грамматика FunctionDeclaration
выглядит так:
function Identifier ( FormalParameterListopt ) { FunctionBody }
И FunctionExpression
с:
function Identifieropt ( FormalParameterListopt ) { FunctionBody }
Как вы можете видеть, токен Identifier
(Identifier opt ) FunctionExpression
является необязательным, поэтому мы можем иметь выражение функции без определенного имени:
(function () {
alert(2 + 2);
}());
Или именованное выражение функции:
(function foo() {
alert(2 + 2);
}());
Круглые скобки (формально называемые оператором группировки ) могут заключать только выражения, и вычисляется выражение функции.
Два производства грамматики могут быть неоднозначными, и они могут выглядеть точно так же, например:
function foo () {} // FunctionDeclaration
0,function foo () {} // FunctionExpression
Парсер знает, является ли он FunctionDeclaration
или a FunctionExpression
, в зависимости от контекста, в котором он появляется.
В приведенном выше примере второй является выражением, поскольку оператор запятой также может обрабатывать только выражения.
С другой стороны, FunctionDeclaration
s может фактически появляться только в так называемом Program
коде, что означает код снаружи в глобальной области видимости и внутри FunctionBody
других функций.
Следует избегать функций внутри блоков, поскольку они могут привести к непредсказуемому поведению, например:
if (true) {
function foo() {
alert('true');
}
} else {
function foo() {
alert('false!');
}
}
foo(); // true? false? why?
Приведенный выше код на самом деле должен генерировать a SyntaxError
, поскольку a Block
может содержать только операторы (а спецификация ECMAScript не определяет какой-либо оператор функции), но большинство реализаций являются терпимыми и просто возьмут вторую функцию, которая предупреждает 'false!'
.
Реализации Mozilla -Rhino, SpiderMonkey, имеют другое поведение. Их грамматика содержит нестандартный оператор Function, означающий, что функция будет оцениваться во время выполнения , а не во время анализа, как это происходит с FunctionDeclaration
s. В этих реализациях мы получим первую определенную функцию.
Функции могут быть объявлены по-разному, сравните следующее :
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;
};