[Javascript] for문과 setTimeout 동시에 쓸 때 var와 let의 차이

Jiyon Lee·2021년 2월 7일
6
post-thumbnail

var과 let의 스코프

var은 함수레벨 스코프를 let은 블록레벨 스코프를 가집니다.
여기서 블록이란 함수, if문, for문, while문 등 중괄호로 묶은 부분을 의미합니다.

var는 for문에서 스코프를 따로 갖지 않기 때문에 의도치 않게 전역변수의 값이 변경될 수 있습니다.
let은 for문 안에서 무슨 행동을 하건 전역변수에는 영향을 미치지 않습니다.

var i = 1;         // 전역변수

for (var i = 0; i < 5; i++) {
  console.log(i);  // 0, 1, 2, 3, 4
}

console.log(i);    // 5  <-- 전역변수 i의 값이 변경되었다 ! 

let i = 1;

for (let i = 0; i < 5; i++) {
  console.log(i);  // 0, 1, 2, 3, 4
}

console.log(i);   // 1  <-- 전역변수 i의 값이 그대로이다.

for문과 setTimeout 동시에 쓰는 상황

var의 문제점

var의 특성 때문에 그동안은 for문과 setTimeout 혹은 setInterval을 같이 쓰는 상황에서 클로저 문제가 발생했습니다.

for (var i = 0; i < 10; i++) {
  setTimeout(() => {
    console.log(i);     // ??? 
  }, (i + 1) * 1000);
}

위 예제의 원래 의도는 1초마다 0, 1, 2, ... 9 가 출력되는 것입니다.
하지만 실행해보면 1초마다 10이 10번 반복해서 출력됩니다. // 10, 10, 10, 10, ....

순서를 자세히 알아보기 위해 이곳저곳에 console.log를 넣어보겠습니다.

for (var i = 0; i < 10; i++) {
  console.log('for문 바로 밑');
  setTimeout(() => {
    console.log(i);     
    console.log('setTimeout 안');
  }, (i + 1) * 1000);
  console.log('setTimeout 빠져나와서');
}
for문 바로 밑
setTimeout 빠져나와서    // 바로 10번 출력

10
setTimeout 안           // 1초마다 10번 출력

for문이 다 돌고 나서야, 즉 i가 10이 되고 나서야 setTimeout를 실행하는 것을 확인할 수 있습니다.
이는 비동기 관련 문제입니다. for문이 시작되고 나서 setTimeout의 콜백함수도 1초 후에 시작됩니다. 하지만 for문은 엄청나게 빠른 속도로 돌기 떄문에 setTimeout은 이미 다 변해버린 i 를 볼 수밖에 없습니다. 그렇기 때문에 애꿎은 10만 반복해서 출력합니다.

let으로 해결

위 코드에서 var만 let으로 변경해 보겠습니다.

for (let i = 0; i < 10; i++) {
  setTimeout(() => {
    console.log(i);     // 0, 1, 2, ... 9  <-- 1초마다 출력
  }, (i + 1) * 1000);
}

원하는 대로 동작합니다!
let으로 바꿨다 하더라도 비동기때문에 for문이 실행이 된 후 setTimeout 내부가 실행됩니다.

다른점은 이번에는 let을 이용했기 때문에 for문의 중괄호에 효력이 생겼습니다.
for문이 돌면서 i 가 0인 스코프, 1인 스코프, 2인 스코프 ... 등등을 생성합니다.
이제 setTimeout함수가 실행되면 i 를 for문의 스코프 안에서 찾기 때문에 순서대로 출력이 됩니다.

참고

코드종님 유튜브 https://www.youtube.com/watch?v=RZ3gXcI1MZY

profile
이사했습니다🚚🚛 https://yonyas.github.io/ 📧jiyonlee.d@gmail.com

1개의 댓글

comment-user-thumbnail
2022년 4월 24일

정보감사합니다~

답글 달기