Como fazer closures em JavaScript lembrarem o valor da variável de sua iteração em um loop?
Por que o problema ocorre?
O problema está relacionado a como closures e o escopo da variável declarada com var funcionam. A palavra-chave var tem escopo de função, não de bloco. No loop for, a variável i é a mesma para todas as iterações. Quando o evento de clique é disparado, o loop já terminou e i tem o valor final (o número total de botões). Como a função callback captura a referência à variável i (não seu valor no momento da criação), todas as funções veem o mesmo valor final.
Como corrigir?
Existem várias soluções. A mais comum é usar let em vez de var, pois let tem escopo de bloco e cria uma nova variável para cada iteração:
for (let i = 0; i < buttons.length; i++) {
buttons[i].addEventListener('click', function() {
console.log('Botão número ' + i);
});
}
Outra abordagem é usar uma IIFE (Immediately Invoked Function Expression) para capturar o valor de i em cada iteração:
for (var i = 0; i < buttons.length; i++) {
(function(index) {
buttons[index].addEventListener('click', function() {
console.log('Botão número ' + index);
});
})(i);
}
Ou usar forEach que já fornece o índice como parâmetro:
buttons.forEach(function(button, index) {
button.addEventListener('click', function() {
console.log('Botão número ' + index);
});
});