Como funciona esta syntax JavaScript / JQuery: (function (window, undefined) {}) (window)?

Você já deu uma olhada sob o capô no código fonte do JQuery 1.4 e percebeu como ele é encapsulado da seguinte maneira:

(function( window, undefined ) { //All the JQuery code here ... })(window); 

Eu li um artigo sobre JavaScript Namespacing e outro chamado ” Um par importante de Parens “, então eu sei um pouco sobre o que está acontecendo aqui.

Mas eu nunca vi essa syntax particular antes. O que é isso undefined fazendo lá? E por que a window precisa ser passada e depois aparecer no final novamente?

O indefinido é uma variável normal e pode ser alterado simplesmente com undefined = "new value"; . Portanto, o jQuery cria uma variável “indefinida” local que é REALMENTE indefinida.

A variável de janela é feita local por motivos de desempenho. Porque quando o JavaScript procura uma variável, ela passa primeiro pelas variables ​​locais até encontrar o nome da variável. Quando não é encontrado, o JavaScript passa pelo próximo escopo, etc., até que ele seja filtrado pelas variables ​​globais. Portanto, se a variável de janela for feita local, o JavaScript poderá procurá-la mais rapidamente. Mais informações: Acelere seu JavaScript – Nicholas C. Zakas

Indefinido

Declarar undefined como um argumento, mas nunca passar um valor para ele, garante que ele seja sempre indefinido, já que é simplesmente uma variável no escopo global que pode ser sobrescrita. Isso faz com que a === undefined uma alternativa segura para o typeof a == 'undefined' , o que economiza alguns caracteres. Ele também torna o código mais amigável para minificadores, já que o undefined pode ser reduzido para u por exemplo, economizando mais alguns caracteres.

Janela

A passagem da window como argumento mantém uma cópia no escopo local, o que afeta o desempenho: http://jsperf.com/short-scope . Todos os accesss à window agora terão que percorrer um nível a menos da cadeia de escopo. Como com o undefined , uma cópia local novamente permite uma minificação mais agressiva.


Nota:

Embora isso possa não ter sido a intenção dos desenvolvedores da jQuery, a passagem da window permite que a biblioteca seja mais facilmente integrada em ambientes Javascript do lado do servidor, por exemplo, node.js – onde não há nenhum object de window global. Em tal situação, apenas uma linha precisa ser alterada para replace o object da window por outro. No caso do jQuery, um object mock window pode ser criado e passado para o propósito de raspar HTML (uma biblioteca como jsdom pode fazer isso).

Outros explicaram undefined . undefined é como uma variável global que pode ser redefinida para qualquer valor. Essa técnica é para impedir que todas as verificações indefinidas se quebrem se alguém escreveu, undefined = 10 algum lugar. Um argumento que nunca é passado é garantido como real undefined independentemente do valor da variável undefined .

O motivo para passar a janela pode ser ilustrado com o exemplo a seguir.

 (function() { console.log(window); ... ... ... var window = 10; })(); 

O que o log do console? O valor do object da window certo? Errado! 10? Errado! Ele registra undefined . O interpretador Javascript (ou compilador JIT) o reescreve desta maneira –

 (function() { var window; //and every other var in this function console.log(window); ... ... ... window = 10; })(); 

No entanto, se você obtiver a variável window como argumento, não haverá var e, portanto, não haverá surpresas.

Eu não sei se o jQuery está fazendo isso, mas se você está redefinindo a variável local window em qualquer lugar em sua function por qualquer razão, é uma boa idéia pegar emprestada do escopo global.

window é passada assim apenas no caso de alguém decidir redefinir o object de janela no IE, eu assumo o mesmo para undefined , no caso de ser reatribuído de alguma forma mais tarde.

A window superior nesse script é apenas nomear o argumento “janela”, um argumento que é mais local que a referência de window global e o que o código dentro desse fechamento usará. A window no final está realmente especificando o que passar pelo primeiro argumento, neste caso, o significado atual da window … a esperança é que você não tenha estragado a window antes que isso aconteça.

Isso pode ser mais fácil de se pensar, mostrando o caso mais típico usado no jQuery, .noConflict() plugin .noConflict() , então para a maioria do código você ainda pode usar $ , mesmo que isso signifique algo diferente de jQuery fora deste escopo:

 (function($) { //inside here, $ == jQuery, it was passed as the first argument })(jQuery); 

Testado com as iterações de 1000000. Esse tipo de localização não teve efeito no desempenho. Nem mesmo um milésimo de segundo nas iterações de 1000000. Isso é simplesmente inútil.