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