Hoje quero comentar uma questão muito comum em entrevistas de JavaScript.
Qual é a saída desse código?
const arr = ['a', 'b', 'c', 'd']
for (var i = 0; i < arr.length; i++) {
setTimeOut(() => {
console.log(i, arr[i])
}, 0)
}
console.log('out', i)
Detalhe que estamos utilizando um setTimeOut com um zero, mas poderia ser qualquer valor.
O primeiro detalhe é que percebemos que o out saiu primeiro com o número 4. O 'var' foi definido dentro do for, porém eu consegui dar um console log lá é baixo. Podemos chegar a conclusão que ele não respeitou o escopo. Outro ponto importante é que ele aconteceu antes do restante, isso acontece porque sempre que utilizamos o setTimeOut, ele leva essa execução da arrow function para dentro do event loop.
Como o i já está com 4, ele não é um número válido, pois nosso array inicia-se em zero e termina em 3. Por esse motivo virá o seguinte:
out 4
4 undefined
4 undefined
4 undefined
4 undefined
Como arrumamos essa função?
Temos algumas formas de arrumar isso. Existe uma bem simples e algumas que podemos brincar um pouco mais.
A primeira bem simples é trocar o var por let:
for (let i=0; i<arr.length; i++){
setTimeOut(() => {
console.log(i, arr[i])
},0)
Agora funcionou perfeitamente:
0 'a'
1 'b'
2 'c'
3 'd'
Por que essa diferença?
Quando estamos com o var, seria equivalente a quando ele estiver executando o código ele puxa todos os vars pra cima, isso é conhecido como hoisting.
Por esse motivo, sempre que possível, utilize let e const.
Outra maneira seria transformar em setTimeOut em uma maneira que eu consiga injetar as variáveis dentro dele mesmo, como uma self invoked:
setTimeOut(
(function (ii) {
return () => {
console.log(ii, arr[ii])
}
})(i),
0
)
Iremos executar a função e a partir da function o ii vai estar válido. Assim funcionará também do jeito que esperávamos.
Confira o video:
Curta o
DevPleno no Facebook, se inscreva no
canal no YouTube e cadastre seu e-mail para não perder as atualizações. Abraço!