Резюме
Можете ли вы объяснить причину синтаксиса инкапсулированных анонимных функций в JavaScript? Почему это работает, (function(){})();
но это не так function(){}();
?
Что я знаю
В JavaScript создается именованная функция, например:
function twoPlusTwo(){
alert(2 + 2);
}
twoPlusTwo();
Вы также можете создать анонимную функцию и назначить ее переменной:
var twoPlusTwo = function(){
alert(2 + 2);
};
twoPlusTwo();
Вы можете инкапсулировать блок кода, создав анонимную функцию, заключив ее в квадратные скобки и выполнив ее немедленно:
(function(){
alert(2 + 2);
})();
Это полезно при создании модульных сценариев, чтобы не загромождать текущую область или глобальную область потенциально конфликтующими переменными - как в случае сценариев Greasemonkey, плагинов jQuery и т. Д.
Теперь я понимаю, почему это работает. Скобки заключают в себе содержимое и показывают только результат (я уверен, что есть лучший способ описать это), например, с (2 + 2) === 4
.
Что я не понимаю
Но я не понимаю, почему это не работает одинаково хорошо:
function(){
alert(2 + 2);
}();
Можете ли вы объяснить это мне?
источник
Ответы:
Он не работает, потому что он анализируется как a
FunctionDeclaration
, и идентификатор имени объявления функции является обязательным .Когда вы заключаете его в скобки, оно оценивается как a
FunctionExpression
, а выражения функций могут быть именованы или нет.Грамматика
FunctionDeclaration
выглядит так:И
FunctionExpression
с:Как вы можете видеть, токен
Identifier
(Identifier opt )FunctionExpression
является необязательным, поэтому мы можем иметь выражение функции без определенного имени:Или именованное выражение функции:
Круглые скобки (формально называемые оператором группировки ) могут заключать только выражения, и вычисляется выражение функции.
Два производства грамматики могут быть неоднозначными, и они могут выглядеть точно так же, например:
Парсер знает, является ли он
FunctionDeclaration
или aFunctionExpression
, в зависимости от контекста, в котором он появляется.В приведенном выше примере второй является выражением, поскольку оператор запятой также может обрабатывать только выражения.
С другой стороны,
FunctionDeclaration
s может фактически появляться только в так называемомProgram
коде, что означает код снаружи в глобальной области видимости и внутриFunctionBody
других функций.Следует избегать функций внутри блоков, поскольку они могут привести к непредсказуемому поведению, например:
Приведенный выше код на самом деле должен генерировать a
SyntaxError
, поскольку aBlock
может содержать только операторы (а спецификация ECMAScript не определяет какой-либо оператор функции), но большинство реализаций являются терпимыми и просто возьмут вторую функцию, которая предупреждает'false!'
.Реализации Mozilla -Rhino, SpiderMonkey, имеют другое поведение. Их грамматика содержит нестандартный оператор Function, означающий, что функция будет оцениваться во время выполнения , а не во время анализа, как это происходит с
FunctionDeclaration
s. В этих реализациях мы получим первую определенную функцию.Функции могут быть объявлены по-разному, сравните следующее :
1- Функция, определенная конструктором Function, назначенным переменной multiply :
2- Объявление функции функции с именем multiply :
3- Функциональное выражение, присвоенное переменной multiply :
4- Именованное выражение функции func_name , присвоенное переменной multiply :
источник
Несмотря на то, что это старый вопрос и ответ, в нем обсуждается тема, которая по сей день заставляет многих разработчиков зацикливаться. Я не могу сосчитать количество кандидатов в разработчики JavaScript, с которыми я беседовал, которые не могли сказать мне разницу между объявлением функции и выражением функции и которые не имели ни малейшего представления о том, что такое выражение, вызываемое немедленно.
Я хотел бы упомянуть, однако, одну очень важную вещь, которая заключается в том, что фрагмент кода Premasagar не будет работать, даже если он дал ему идентификатор имени.
Причина, по которой это не сработает, состоит в том, что движок JavaScript интерпретирует это как объявление функции, за которым следует совершенно не связанный оператор группировки, который не содержит выражений, а операторы группировки должны содержать выражение. Согласно JavaScript, приведенный выше фрагмент кода эквивалентен следующему.
Еще одна вещь, на которую я хотел бы обратить внимание, которая может быть полезна для некоторых людей, это то, что любой идентификатор имени, который вы предоставляете для выражения функции, практически бесполезен в контексте кода, кроме как внутри самого определения функции.
Конечно, использование идентификаторов имен в определениях функций всегда полезно, когда речь идет об отладке кода, но это совсем другое ... :-)
источник
Хорошие ответы уже опубликованы. Но я хочу отметить, что объявления функций возвращают пустую запись завершения:
Этот факт не легко заметить, потому что большинство способов получить возвращаемое значение преобразуют объявление функции в выражение функции. Однако
eval
показывает это:Вызывать пустую запись о завершении не имеет смысла. Вот почему
function f(){}()
не может работать. На самом деле движок JS даже не пытается вызвать его, скобки считаются частью другого оператора.Но если вы заключите функцию в скобки, она станет выражением функции:
Функциональные выражения возвращают функциональный объект. И поэтому вы можете назвать это:
(function f(){})()
.источник
В javascript это называется выражением немедленного вызова функций (IIFE) .
Чтобы сделать это функциональным выражением, вы должны:
заключите это используя ()
поместите пустой оператор перед ним
присвоить его переменной.
В противном случае оно будет рассматриваться как определение функции, и тогда вы не сможете одновременно вызывать / вызывать его следующим образом:
Вышеуказанное даст вам ошибку. Потому что вы можете только немедленно вызвать выражение функции.
Это может быть достигнуто несколькими способами: Способ 1:
Способ 2:
Способ 3:
способ 4:
Все вышеизложенное немедленно вызовет выражение функции.
источник
У меня есть еще одно небольшое замечание. Ваш код будет работать с небольшим изменением:
Я использую приведенный выше синтаксис вместо более распространенной версии:
потому что мне не удалось заставить отступ работать правильно для файлов javascript в vim. Кажется, что vim не нравятся фигурные скобки внутри открытых скобок.
источник
function
ключевого слова, как объявление функции, и в этом случае завершающий()
элемент интерпретируется как оператор группировки, который, согласно правилам синтаксиса JavaScript, может только и должен содержать выражение JavaScript.()
для согласованности либо «более распространенную версию», на которую вы ссылались, либо вариант, в котором заключен оператор группировки (тот, который настоятельно рекомендует Дуглас Крокфорд): Обычно используются IIFE без присвоения их переменной, и легко забыть включить эти заключительные скобки, если вы не используете их последовательно.Возможно, более короткий ответ будет
является литералом функции, который определяет (анонимную) функцию. Дополнительная пара (), которая интерпретируется как выражение, на верхнем уровне не ожидается, только литералы.
находится в выражении выражения, которое вызывает анонимную функцию.
источник
Выше действительный синтаксис, потому что все, что передается в скобках, рассматривается как выражение функции
Выше недопустимый синтаксис. Поскольку синтаксический анализатор java-скрипта ищет имя функции после ключевого слова функции, так как он ничего не находит, он выдает ошибку.
источник
Вы также можете использовать его как:
или
!
- negation op преобразует определение fn в выражение fn, поэтому вы можете вызвать его немедленно с помощью()
. То же, что использование0,fn def
илиvoid fn def
источник
Их можно использовать с параметрами-аргументами, такими как
будет результатом как 7
источник
Эти дополнительные скобки создают дополнительные анонимные функции между глобальным пространством имен и анонимной функцией, которая содержит код. А в функциях Javascript, объявленных внутри других функций, есть доступ только к пространству имен родительской функции, которая их содержит. Поскольку существует дополнительный объект (анонимная функция) между глобальной областью действия и фактической областью действия кода, она не сохраняется.
источник