O problema que você está enfrentando tem a ver com o conceito de "closures" (fechamentos) em JavaScript. Vou explicar o que está acontecendo no código e o motivo pelo qual o uso de uma const dentro do loop resolve o problema.
No código original, você está usando um loop while
para percorrer todas as teclas e adicionar um evento de clique a cada uma delas. No entanto, o evento de clique está chamando a função playSound
passando o valor do index
como argumento. O index
é uma variável que está sendo incrementada a cada iteração do loop e, quando a função playSound
é executada, ela usará o valor atual de index
.
O problema é que, quando ocorre um clique em uma das teclas, a função playSound
é chamada, mas o valor do index
já foi incrementado para o número total de teclas (ou seja, teclas.length
). Portanto, a função playSound
sempre recebe o mesmo valor para idSound
, que é o valor de teclas[teclas.length].classList[1]
, o que provavelmente não existe, gerando o erro que você viu no console.
Para resolver esse problema, a alternativa com o uso de uma const dentro do loop é uma forma de criar um escopo separado para cada iteração do loop. Ao fazer isso, o valor do index
é capturado como uma cópia dentro do escopo da constante, e cada função de clique criada dentro do loop terá acesso a esse valor específico.
Aqui está o exemplo corrigido usando uma const dentro do loop:
const teclas = document.querySelectorAll('.tecla');
function playSound(idSound) {
document.querySelector('#som_' + idSound).play();
}
for (let index = 0; index < teclas.length; index++) {
teclas[index].onclick = function () {
playSound(teclas[index].classList[1]);
};
}
Ao usar let index = 0
, o index
é criado como uma variável de bloco no escopo do loop for
, e cada iteração terá um valor diferente para index
. Isso evita o problema de closure e faz com que o código funcione corretamente.