O que os parênteses em torno de uma declaração de object / function / class significam?

Sou novo em JavaScript e YUI . Nos exemplos de biblioteca YUI, você pode encontrar muitos usos dessa construção:

(function() { var Dom = YAHOO.util.Dom, Event = YAHOO.util.Event, layout = null, ... })(); 

Eu acho que o último par de parênteses é para executar a function logo após a declaração.

… Mas e o conjunto anterior de parênteses em torno da declaração de function?

Eu acho que é uma questão de escopo; isto é esconder variables ​​internas para funções externas e possivelmente objects globais. É isso? Mais geralmente, quais são as mecânicas desses parênteses?

É uma function anônima auto-executável. O primeiro conjunto de parênteses contém as expressões a serem executadas e o segundo conjunto de parênteses executa essas expressões.

É uma construção útil ao tentar ocultar variables ​​do namespace pai. Todo o código dentro da function está contido no escopo privado da function, o que significa que não pode ser acessado de forma alguma fora da function, tornando-a verdadeiramente privada.

Vejo:

http://en.wikipedia.org/wiki/Closure_%28computer_science%29

http://peter.michaux.ca/articles/javascript-namespacing

Andy Hume praticamente deu a resposta, eu só quero adicionar mais alguns detalhes.

Com essa construção, você está criando uma function anônima com seu próprio ambiente de avaliação ou fechamento e, em seguida, avalie-a imediatamente. O bom disso é que você pode acessar as variables ​​declaradas antes da function anônima, e você pode usar variables ​​locais dentro desta function sem sobrescrever acidentalmente uma variável existente.

O uso da palavra-chave var é muito importante, porque em JavaScript todas as variables ​​são globais por padrão, mas com a palavra-chave você cria uma nova variável com escopo léxico , isto é, é visível pelo código entre as duas chaves . No seu exemplo, você está essencialmente criando aliases curtos para os objects na biblioteca YUI, mas tem usos mais poderosos.

Eu não quero deixar você sem um exemplo de código, então vou colocar aqui um exemplo simples para ilustrar um fechamento:

 var add_gen = function(n) { return function(x) { return n + x; }; }; var add2 = add_gen(2); add2(3); // result is 5 

O que está acontecendo aqui? Na function add_gen você está criando uma outra function que simplesmente adiciona o número n ao seu argumento. O truque é que, nas variables ​​definidas na lista de parâmetros da function, atuem como variables ​​de escopo léxico, como as definidas com var .

A function retornada é definida entre as chaves da function add_gen para que tenha access ao valor de n mesmo depois que a function add_gen tenha terminado a execução, é por isso que você obterá 5 ao executar a última linha do exemplo.

Com a ajuda de parâmetros de function que estão no escopo léxico, você pode contornar os “problemas” decorrentes do uso de variables ​​de loop em funções anônimas. Tome um exemplo simples:

 for(var i=0; i<5; i++) { setTimeout(function(){alert(i)}, 10); } 

O resultado "esperado" poderia ser os números de zero a quatro, mas você obtém quatro instâncias de cinco. Isso acontece porque a function anônima em setTimeout e o loop for usam a mesma variável i , então, no momento em que as funções forem avaliadas, eu serei 5.

Você pode obter o resultado ingenuamente esperado usando a técnica em sua pergunta e o fato de que os parâmetros de function são lexicamente definidos. (Eu usei essa abordagem em outra resposta )

 for(var i=0; i<5; i++) { setTimeout( (function(j) { return function(){alert(j)}; })(i), 10); } 

Com a avaliação imediata da function externa, você está criando uma variável completamente independente chamada j em cada iteração, e o valor atual de i será copiado para essa variável, assim você obterá o resultado que era ingenuamente esperado da primeira tentativa.

Eu sugiro que você tente entender o excelente tutorial em http://ejohn.org/apps/learn/ para entender melhor os fechamentos, que é onde eu aprendi muito muito.

… mas e os parenteses da rodada anterior em torno de toda a declaração de function?

Especificamente, faz o JavaScript interpretar a construção ‘function () {…}’ como uma expressão de function anônima inline. Se você omitiu os colchetes:

 function() { alert('hello'); }(); 

Você obteria um erro de syntax, porque o analisador JS veria a palavra-chave ‘function’ e presumiria que você estivesse iniciando uma instrução de function do formulário:

 function doSomething() { } 

… e você não pode ter uma instrução de function sem um nome de function.

expressões de function e instruções de function são duas construções diferentes que são tratadas de maneiras muito diferentes. Infelizmente a syntax é quase idêntica, então não é apenas confuso para o programador, até mesmo o analisador tem dificuldade em dizer o que você quer dizer!

Juts para acompanhar o que Andy Hume e outros disseram:

O ‘()’ em torno da function anônima é o ‘operador de agrupamento’ conforme definido na seção 11.1.6 da especificação ECMA: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262 .pdf

Obtido textualmente a partir dos documentos:

11.1.6 O Operador de Agrupamento

A ExpressExpression de produção: ( Expression ) é avaliada da seguinte maneira:

  1. Retorna o resultado da avaliação da expressão . Isso pode ser do tipo Reference.

Neste contexto, a function é tratada como uma expressão.

Algumas considerações sobre o assunto:

  • O parêntese:

    O navegador (engine / parser) associa a function keyword com

     [optional name]([optional parameters]){...code...} 

    Portanto, em uma expressão como function () {} (), o último parêntese não faz sentido.

    Agora pense em

     name=function(){} ; name() !? 

Sim, o primeiro par de parênteses força a function anônima a se transformar em uma variável (expressão armazenada) e a segunda lança avaliação / execução, então ( function () {} ) () faz sentido.

  • A utilidade: ?

    1. Para executar algum código na carga e isolar as variables ​​usadas do resto da página, especialmente quando conflitos de nome são possíveis;

    2. Substitua eval (“string”) por

      (nova function (“string”)) ()

    3. Enrole o código longo para o operador ” = ?: ” como:

      result = exp_to_test? (function () {… long_code …}) (): (function () {…}) ();

Os primeiros parênteses são para, se você quiser, ordem de operações. O ‘resultado’ do conjunto de parênteses em torno da definição da function é a própria function que, de fato, o segundo conjunto de parênteses é executado.

Quanto ao porquê é útil, eu não sou o suficiente de um assistente de JavaScript para ter alguma ideia. : P

Veja esta questão . O primeiro conjunto de parênteses não é necessário se você usar um nome de function, mas uma function sem nome requer essa construção e os parênteses servem para que os codificadores percebam que estão exibindo uma function de auto-invocação ao navegar pelo código (consulte um dos melhores recomendação de práticas ).