Em resumo
Sumário
Em sua forma mais simples, essa técnica visa agrupar o código dentro de um escopo de função .
Ajuda a diminuir as chances de:
- colidindo com outros aplicativos / bibliotecas
- poluentes escopo superior (provavelmente global)
Ele não detectar quando o documento está pronto - não é algum tipo de document.onload
nemwindow.onload
É comumente conhecido como um Immediately Invoked Function Expression (IIFE)
ouSelf Executing Anonymous Function
.
Código explicado
var someFunction = function(){ console.log('wagwan!'); };
(function() { /* function scope starts here */
console.log('start of IIFE');
var myNumber = 4; /* number variable declaration */
var myFunction = function(){ /* function variable declaration */
console.log('formidable!');
};
var myObject = { /* object variable declaration */
anotherNumber : 1001,
anotherFunc : function(){ console.log('formidable!'); }
};
console.log('end of IIFE');
})(); /* function scope ends */
someFunction(); // reachable, hence works: see in the console
myFunction(); // unreachable, will throw an error, see in the console
myObject.anotherFunc(); // unreachable, will throw an error, see in the console
No exemplo acima, qualquer variável definida na função (ou seja, declarada usando var
) será "privada" e acessível somente dentro do escopo da função (como Vivin Paliath coloca). Em outras palavras, essas variáveis não são visíveis / alcançáveis fora da função. Veja demonstração ao vivo .
Javascript tem escopo de função. "Parâmetros e variáveis definidos em uma função não são visíveis fora da função e que uma variável definida em qualquer lugar dentro de uma função é visível em qualquer lugar dentro da função." (de "Javascript: as boas partes").
Mais detalhes
Código Alternativo
No final, o código publicado anteriormente também pode ser feito da seguinte maneira:
var someFunction = function(){ console.log('wagwan!'); };
var myMainFunction = function() {
console.log('start of IIFE');
var myNumber = 4;
var myFunction = function(){ console.log('formidable!'); };
var myObject = {
anotherNumber : 1001,
anotherFunc : function(){ console.log('formidable!'); }
};
console.log('end of IIFE');
};
myMainFunction(); // I CALL "myMainFunction" FUNCTION HERE
someFunction(); // reachable, hence works: see in the console
myFunction(); // unreachable, will throw an error, see in the console
myObject.anotherFunc(); // unreachable, will throw an error, see in the console
Veja demonstração ao vivo .
As raízes
Iteração 1
Um dia, alguém provavelmente pensou "deve haver uma maneira de evitar nomear 'myMainFunction', já que tudo o que queremos é executá-lo imediatamente".
Se você voltar ao básico, descobrirá que:
expression
: algo avaliando um valor. ie3+11/x
statement
: linha (s) de código fazendo algo, mas não avalia como um valor. ieif(){}
Da mesma forma, as expressões de função são avaliadas para um valor. E uma conseqüência (presumo?) É que eles podem ser imediatamente invocados:
var italianSayinSomething = function(){ console.log('mamamia!'); }();
Portanto, nosso exemplo mais complexo se torna:
var someFunction = function(){ console.log('wagwan!'); };
var myMainFunction = function() {
console.log('start of IIFE');
var myNumber = 4;
var myFunction = function(){ console.log('formidable!'); };
var myObject = {
anotherNumber : 1001,
anotherFunc : function(){ console.log('formidable!'); }
};
console.log('end of IIFE');
}();
someFunction(); // reachable, hence works: see in the console
myFunction(); // unreachable, will throw an error, see in the console
myObject.anotherFunc(); // unreachable, will throw an error, see in the console
Veja demonstração ao vivo .
Iteração 2
O próximo passo é o pensamento "por que ter var myMainFunction =
se nem sequer o usamos !?".
A resposta é simples: tente remover isso, como abaixo:
function(){ console.log('mamamia!'); }();
Veja demonstração ao vivo .
Não funcionará porque "declarações de função não são invocáveis" .
O truque é que, removendo var myMainFunction =
, transformamos a expressão da função em uma declaração de função . Consulte os links em "Recursos" para obter mais detalhes sobre isso.
A próxima pergunta é "por que não posso mantê-lo como uma expressão de função com algo diferente var myMainFunction =
?
A resposta é "você pode" e, na verdade, existem várias maneiras de fazer isso: adicionar a +
, a !
, a -
ou talvez colocar parênteses (como agora é feito por convenção) e muito mais, acredito. Como exemplo:
(function(){ console.log('mamamia!'); })(); // live demo: jsbin.com/zokuwodoco/1/edit?js,console.
ou
+function(){ console.log('mamamia!'); }(); // live demo: jsbin.com/wuwipiyazi/1/edit?js,console
ou
-function(){ console.log('mamamia!'); }(); // live demo: jsbin.com/wejupaheva/1/edit?js,console
Assim, depois que a modificação relevante é adicionada ao que era nosso "Código Alternativo", retornamos exatamente ao mesmo código que o usado no exemplo "Código Explicado"
var someFunction = function(){ console.log('wagwan!'); };
(function() {
console.log('start of IIFE');
var myNumber = 4;
var myFunction = function(){ console.log('formidable!'); };
var myObject = {
anotherNumber : 1001,
anotherFunc : function(){ console.log('formidable!'); }
};
console.log('end of IIFE');
})();
someFunction(); // reachable, hence works: see in the console
myFunction(); // unreachable, will throw an error, see in the console
myObject.anotherFunc(); // unreachable, will throw an error, see in the console
Leia mais sobre Expressions vs Statements
:
Escopos de desmistificação
Uma coisa que podemos nos perguntar é "o que acontece quando você NÃO define a variável 'adequadamente' dentro da função - ou seja, faz uma atribuição simples?"
(function() {
var myNumber = 4; /* number variable declaration */
var myFunction = function(){ /* function variable declaration */
console.log('formidable!');
};
var myObject = { /* object variable declaration */
anotherNumber : 1001,
anotherFunc : function(){ console.log('formidable!'); }
};
myOtherFunction = function(){ /* oops, an assignment instead of a declaration */
console.log('haha. got ya!');
};
})();
myOtherFunction(); // reachable, hence works: see in the console
window.myOtherFunction(); // works in the browser, myOtherFunction is then in the global scope
myFunction(); // unreachable, will throw an error, see in the console
Veja demonstração ao vivo .
Basicamente, se uma variável que não foi declarada em seu escopo atual tiver um valor atribuído, "uma pesquisa na cadeia de escopo ocorrerá até encontrar a variável ou atingir o escopo global (no momento em que será criada)".
Quando em um ambiente de navegador (versus um ambiente de servidor como nodejs), o escopo global é definido pelo window
objeto. Por isso, podemos fazer window.myOtherFunction()
.
Minha dica "Boas práticas" sobre este tópico é sempre usar var
ao definir algo : seja um número, objeto ou função e até mesmo no escopo global. Isso torna o código muito mais simples.
Nota:
- O javascript não possui
block scope
(Atualização: variáveis locais do escopo do bloco adicionadas no ES6 .)
- javascript possui apenas
function scope
& global scope
( window
escopo em um ambiente de navegador)
Leia mais sobre Javascript Scopes
:
Recursos
Próximos passos
Depois de obter esse IIFE
conceito, ele leva ao module pattern
, o que geralmente é feito ao alavancar esse padrão IIFE. Diverta-se :)