exemplo de fechamento javascript e cadeia de escopo
-
21-12-2019 - |
Pergunta
Alguém pode me explicar (de forma clara e concisa) por que esse código funciona dessa maneira?Eu venho de uma experiência fortemente tipada em Java (6 e 7), onde os fechamentos não existem e não funcionam da maneira que funcionam em javascript.Acho que os conceitos relacionados a esta questão são:fechamentos e cadeia de escopo.
Aqui está o exemplo:
var myfuncs = function() {
var funcs = []
var i;
for (i = 0; i < 10; i++) {
funcs[i] = function() { console.log(i); }
}
return funcs;
}
var allfuncs = myfuncs();
allfuncs.forEach(function(fn) { fn(); });
O exemplo acima registra 9 (10 vezes), mas a expectativa e minha própria intuição pensavam que registraria 0-9.
Por que isso funciona dessa maneira em Javascript?Os fechamentos são muito poderosos, mas estou tentando entender o conceito de uma vez por todas!Um exemplo ligeiramente modificado produz a saída correta, mas por quê?
var myfuncs = function() {
var funcs = []
var i;
for (i = 0; i < 10; i++) {
funcs[i] = (function(index) { console.log(index); })(i);
}
return funcs;
}
var allfuncs = myfuncs();
allfuncs.forEach(function(fn) { fn(); });
Os encerramentos não são exclusivos do Javascript, mas quero ver por que eles são poderosos no contexto de quando o javascript é realmente escrito para interagir com o navegador/dom.
Alguém tem exemplos bons e práticos de como podemos aplicar a técnica de fechamento na interface com o navegador/dom?
Obrigado.
Solução
Nos exemplos que você tem, é muito simples.
No seu primeiro exemplo, há apenas uma variável i
e tudo faz referência a esse valor único.Então..ele imprime o número 9
dez vezes.Cada função capturou um compartilhado valor de i
isso muda.
No segundo exemplo você está usando um encerramento.Cada função possui uma variável privada chamada index
que recebe - e aqui está a parte importante - um cópia de do valor i
.
Então, você consegue 0
através 9
porque são dez funções, cada uma com uma particularidade index
variável e cada um desses index
variáveis obtêm um instantâneo de i
como existia na época.
Esta forma mais longa de fechamento pode ajudar:
function myFactory(index) {
return function() {
console.log(index);
}
}
var myfuncs = function() {
var funcs = []
var i;
for (i = 0; i < 10; i++) {
funcs[i] = myFactory(i);
}
return funcs;
}
var allfuncs = myfuncs();
allfuncs.forEach(function(fn) { fn(); });