Sumário
Você pode explicar o raciocínio por trás da sintaxe para funções anônimas encapsuladas em JavaScript? Por que isso funciona: (function(){})();
mas isso não function(){}();
:?
O que eu sei
Em JavaScript, cria-se uma função nomeada como esta:
function twoPlusTwo(){
alert(2 + 2);
}
twoPlusTwo();
Você também pode criar uma função anônima e atribuí-la a uma variável:
var twoPlusTwo = function(){
alert(2 + 2);
};
twoPlusTwo();
Você pode encapsular um bloco de código criando uma função anônima, colocando-a entre colchetes e executando-a imediatamente:
(function(){
alert(2 + 2);
})();
Isso é útil ao criar scripts modularizados, para evitar sobrecarregar o escopo atual ou global, com variáveis potencialmente conflitantes - como no caso de scripts Greasemonkey, plugins jQuery, etc.
Agora entendo por que isso funciona. Os colchetes incluem o conteúdo e expõem apenas o resultado (tenho certeza de que há uma maneira melhor de descrevê-lo), como com (2 + 2) === 4
.
O que eu não entendo
Mas não entendo por que isso não funciona igualmente:
function(){
alert(2 + 2);
}();
Você pode me explicar isso?
fonte
Respostas:
Não funciona porque está sendo analisado como ae
FunctionDeclaration
o identificador de nome das declarações de função é obrigatório .Quando você o coloca entre parênteses, ele é avaliado como
FunctionExpression
ae as expressões de função podem ser nomeadas ou não.A gramática de a
FunctionDeclaration
é assim:E
FunctionExpression
s:Como você pode ver, o token
Identifier
(Identifier opt )FunctionExpression
é opcional, portanto, podemos ter uma expressão de função sem um nome definido:Ou expressão da função nomeada :
Os parênteses (formalmente chamado de operador de agrupamento ) podem envolver apenas expressões e uma expressão de função é avaliada.
As duas produções gramaticais podem ser ambíguas e podem parecer exatamente iguais, por exemplo:
O analisador sabe se é um
FunctionDeclaration
ou umFunctionExpression
, dependendo do contexto em que aparece.No exemplo acima, o segundo é uma expressão porque o operador Vírgula também pode manipular apenas expressões.
Por outro lado,
FunctionDeclaration
s poderia aparecer apenas noProgram
código " ", significando código fora do escopo global e dentroFunctionBody
de outras funções.As funções dentro dos blocos devem ser evitadas, pois podem levar a um comportamento imprevisível, por exemplo:
O código acima deve realmente produzir a
SyntaxError
, uma vez que aBlock
pode conter apenas instruções (e a especificação ECMAScript não define nenhuma instrução de função), mas a maioria das implementações é tolerante e simplesmente aceita a segunda função, a que alerta'false!'
.As implementações do Mozilla - Rhino, SpiderMonkey, - têm um comportamento diferente. Sua gramática contém uma Declaração de Função não padrão , o que significa que a função será avaliada no tempo de execução , não no tempo de análise, como acontece com
FunctionDeclaration
s. Nessas implementações, obteremos a primeira função definida.As funções podem ser declaradas de diferentes maneiras; compare o seguinte :
1- Uma função definida com o construtor Function atribuído à variável multiplica :
2- Uma declaração de função de uma função denominada multiply :
3- Uma expressão de função atribuída à variável multiplica :
4- Uma expressão de função nomeada func_name , atribuída à variável multiply :
fonte
Embora essa seja uma pergunta e resposta antigas, ele discute um tópico que até hoje gera muitos desenvolvedores em um loop. Não posso contar o número de candidatos a desenvolvedor JavaScript que entrevistei que não conseguiam me dizer a diferença entre uma declaração de função e uma expressão de função e que não tinham idéia do que é uma expressão de função imediatamente invocada.
Gostaria de mencionar, no entanto, uma coisa muito importante que é que o trecho de código de Premasagar não funcionaria, mesmo que ele tivesse dado um identificador de nome.
A razão pela qual isso não funcionou é que o mecanismo JavaScript interpreta isso como uma declaração de função seguida por um operador de agrupamento completamente não relacionado que não contém expressão, e os operadores de agrupamento devem conter uma expressão. De acordo com o JavaScript, o trecho de código acima é equivalente ao seguinte.
Outra coisa que gostaria de salientar que pode ser útil para algumas pessoas é que qualquer identificador de nome que você forneça para uma expressão de função é praticamente inútil no contexto do código, exceto dentro da própria definição de função.
Obviamente, o uso de identificadores de nome com suas definições de função é sempre útil quando se trata de código de depuração, mas isso é algo completamente diferente ... :-)
fonte
Ótimas respostas já foram postadas. Mas quero observar que as declarações de função retornam um registro de conclusão vazio:
Esse fato não é fácil de observar, porque a maioria das maneiras de tentar obter o valor retornado converterá a declaração da função em uma expressão de função. No entanto,
eval
mostra:Chamar um registro de conclusão vazio não faz sentido. É por isso
function f(){}()
que não pode funcionar. De fato, o mecanismo JS nem tenta chamá-lo, os parênteses são considerados parte de outra instrução.Mas se você envolver a função entre parênteses, ela se tornará uma expressão de função:
As expressões de função retornam um objeto de função. E, portanto, você pode chamá-lo:
(function f(){})()
.fonte
Em javascript, isso é chamado de Expressão de Função Imediatamente Invocada (IIFE) .
Para torná-lo uma expressão de função, você deve:
coloque-o usando ()
coloque um operador vazio antes de
atribua-o a uma variável.
Caso contrário, será tratado como definição de função e você não poderá chamá-lo / invocá-lo ao mesmo tempo da seguinte maneira:
O texto acima dará a você erro. Porque você pode invocar apenas uma expressão de função imediatamente.
Isso pode ser alcançado de duas maneiras: Maneira 1:
Caminho 2:
Caminho 3:
caminho 4:
Tudo acima invocará imediatamente a expressão da função.
fonte
Eu tenho apenas outro pequeno comentário. Seu código funcionará com uma pequena alteração:
Eu uso a sintaxe acima em vez da versão mais amplamente difundida:
porque não consegui fazer o recuo funcionar corretamente para arquivos javascript no vim. Parece que o vim não gosta das chaves nos parênteses abertos.
fonte
function
palavra - chave como uma declaração de função. Nesse caso, o final()
é interpretado como um operador de agrupamento , que, de acordo com regras de JavaScript sintaxe, só pode e deve conter uma expressão JavaScript.()
incluída no operador de agrupamento (aquele que Douglas Crockford recomenda fortemente) para obter consistência: é É comum usar IIFEs sem atribuí-los a uma variável, e é fácil esquecer de incluir esses parênteses se você não os usar de forma consistente.Talvez a resposta mais curta seja essa
é uma literal de função que define uma função (anônima). Um par () adicional, que é interpretado como uma expressão, não é esperado no nível superior, apenas literais.
está em um instrução de expressão que chama uma função anônima.
fonte
Acima é uma sintaxe válida, porque qualquer coisa passada entre parênteses é considerada como expressão de função.
Acima não é uma sintaxe válida. Como o analisador de sintaxe do script java procura o nome da função após a palavra-chave da função, pois não encontra nada, gera um erro.
fonte
Você também pode usá-lo como:
ou
!
- negation op converte a definição fn em expressão fn; portanto, você pode invocá-la imediatamente com()
. O mesmo que usar0,fn def
ouvoid fn def
fonte
Eles podem ser usados com parâmetros-argumentos como
resultaria em 7
fonte
Esses parênteses extras criam funções anônimas extras entre o espaço para nome global e a função anônima que contém o código. E, em funções Javascript declaradas dentro de outras funções, somente é possível acessar o namespace da função pai que as contém. Como existe um objeto extra (função anônima) entre o escopo global e o escopo do código real, não é mantido.
fonte