Mesmo se você for um programador novo, não irá demorar muito quando você trabalhar com JavaScript antes de se deparar com esse padrão:
(function () { // código })();
Ao primeiro encontro provavelmente parecerá bastante confuso, no entanto, o conceito em si é simples.
O padrão é chamado de expressão de função imediatamente invocada (Inglês: Immediate Invoking Function Expression) ou IIFE (pronunciado “iffy”).
Em JavaScript funções podem ser criadas através de uma declaração de função ou uma expressão de função. Uma declaração de função é a maneira “normal” de criar uma função nomeada.
function myFunction () { /* código */ }
Por outro lado, se você está atribuindo uma função a uma variável ou propriedade, você está lidando com uma expressão de função.
var umaFunc= function () { /* código */ }; var objeto = { myFunction: function () { /* código */ } };
Uma função criada no contexto de uma expressão também é uma expressão de função. Por exemplo:
(function () { /* código */ });
A principal coisa sobre expressões JavaScript é que elas retornam valores. Em ambos os casos, acima do valor de retorno da expressão é a função.
Isso significa que, se quisermos invocar a expressão de função imediatamente, precisamos apenas colocar alguns parênteses no final. O que nos traz de volta ao primeiro trecho de código que vimos.
(function () { // código })();
Agora sabemos o que o código está fazendo, mas a pergunta “Por quê?” ainda resta.
A principal razão para usar um IIFE é obter privacidade de dados. Como var variáveis do escopo do JavaScript para sua função de contenção, quaisquer variáveis declaradas no IIFE não podem ser acessadas pelo mundo externo.
(function () { var foo = "bar"; // exibe: "bar" console.log(foo); })(); // Se tentar acessar a variavel, ocorrerá um erro // ReferenceError: foo is not defined console.log(foo);
É claro que, você poderia explicitamente nomear e depois invocar uma função para alcançar os mesmos fins.
function myImmediateFunction () { var foo = "bar"; // exibe: "bar" console.log(foo); } myImmediateFunction(); // Igual ao exemplo anterior, se tentar acessar a variavel, ocorrerá um erro // ReferenceError: foo is not defined console.log(foo);
No entanto, esta abordagem tem algumas desvantagens. Primeiro, ele ocupa desnecessariamente um nome no namespace global, aumentando a possibilidade de colisões de nomes. Em segundo lugar, as intenções deste código não são tão auto-documentadas quanto um IIFE. E terceiro, porque é nomeado e não é auto-documentado, pode acidentalmente ser invocado mais de uma vez.
Vale a pena ressaltar que você também pode facilmente passar argumentos para o IIFE.
var foo = "foo"; (function (innerFoo) { // exibe: "foo" console.log(innerFoo); })(foo);
E essa é a história por trás dos IIFEs. Em breve, estaremos desenvolvendo isso analisando o padrão de módulo em JavaScript.
Tradução: