No post anterior explicamos o que é Closure e como se comporta em relação ao escopo. O exemplo dado pelo W3C demonstrou que, com o uso de Closures, é possível manter o escopo de uma função acessível ao executá-la fora do seu escopo léxico.
Agora que possuímos o entendimento teórico, podemos iniciar a abordagem de exemplos práticos. Vamos começar avaliando o código a seguir; você consegue prever o resultado?
for(var i=0; i< 5; i++) { setTimeout(function timer() { console.log(i); }, i * 1000); }
Esperar que o código acima retorne 0,1,2,..,4 é um erro comum relacionado a má interpretação sobre o comportamento do compilador. Adiantando o resultado, o código acima retorna “5” cinco vezes. Alguns podem acabar pensando que isto é um defeito da engine já que, semanticamente, o código parece atender o que se propôs. Na realidade, o problema está no próprio código e não está relacionado em momento algum com a engine.
Analisando o código, fica evidente que cada chamada de função setTimeout acessa a mesma referência da variável i. Além deste ponto, setTimeout é executado após a execução do loop, ou seja, quando o valor de i é “5”.
Para resolver este problema precisamos que nossa chamada setTimeout seja executada de modo que enxergue o valor correto de i. Precisamos que cada callback de nosso timer tenha um escopo definido sobre cada execução do laço. Para isto, utilizaremos um recurso que nos permite executar uma função no momento em que a mesma é declarada. Isto é conhecido como Immediately-invoked function expression (IIFE). IIFE funciona criando um escopo ao declarar a função e logo em seguida executá-la. Vejamos o exemplo:
for(var i=0; i< 5; i++) { (function(j){ setTimeout(function timer() { console.log(j); }, j*1000); })(i); }
Com o uso da IIFE, conseguimos fechar o escopo de cada callback de timer sobre a execução do nosso laço. O valor de i fica guardado através da referência j, acessível neste escopo criado a cada execução. Desse modo, conseguimos referenciar corretamente os valores desejados para i.
O texto acima foi uma síntese do conteúdo do livro You Don’t Know JavaScript.