목차
for vs while
for | while |
구하고자 하는 값이 정확한 조건이 있는 경우 사용 | 구하고자 하는 값이 정확한 조건을 정확히 모를 경우, 유동적인 경우 사용 |
조건식, 초기값이 블락 안에 모여있어 가독성이 좋다 | 조건식이 흩어져 있어 가독성이 나쁨 |
출처: https://chaeyoung2.tistory.com/67 [공부하는 공작새:티스토리]
이런 사실은 알고는 있는데 자바스크립트에서 while과 for를 사용하는 도중 settimeout을 반복문을 돌리려 하는데 전혀 다른 결과가 나타났다.
let i=0;
while(i<6) {
setTimeout(() => {
console.log(">>>i :", i)
console.log(">>winBalls", winBalls)
const temp = document.createElement('div');
temp.className = 'ball';
temp.textContent = winBalls[i]
$result.append(temp);
}, i*3000);
i++
}
for(let i=0; i<6; i++) {
setTimeout(() => {
console.log(">>index", i)
console.log(">>winBalls", winBalls)
const temp = document.createElement('div');
temp.className = 'ball';
temp.textContent = winBalls[i]
$result.append(temp);
}, i*3000);
}
while은 i가 계속 6으로 콘솔에 나타나고
for은 i가 정상적으로 0~5까지 나타났다.
chatGPT에 물어보고 이해한 내용을 정리하고자 글을 쓴다.
일단 settimeout은 비동기함수이기 때문에 settimeout이 실행되기 전에 while의 반복문이 다 돌아서 마지막 i인 6이 settimeout안에서 실행되는것이다.
이는 클로저라는 개념을 알아야 한다. settimeout내의 화살표함수가 클로저라는건데 이 클로저에서는 i를 현재 while에서 빠르게 반복이 6번이 돈 상태이므로 i를 6으로 인식하고 i를 계속 6으로 나타낸다.
하지만 for문을 보면 let=i; 로 반복이 돌때마다 선언을 하기 때문에 새로운 블록 스코프를 생성되기 때문에 클로저가 필요없다. 즉 for문에서 선언된 변수는 고유한 스코프를 가지고 클로저를 사용하지 않게 된다.
var vs let
var은 함수스코프다.
let은 블록스코프다.
//1
function b() {
var a = 1;
}
console.log(a); //접근x
//2
function b() {
let a = 1;
}
console.log(a); //접근x
//3
if(true) {
var a = 1
}
console.log(a); //접근가능
//4
if(true) {
let a = 1
}
console.log(a); //접근x
//5
for( var i=0; i<5; i++) {}
console.log(i); //접근가능
//6
for( let e=0; i<5; i++) {}
console.log(e); //접근 x
1,2
기본적으로 함수 바깥에서는 접근이 불가능하다.
//if문
3은 var는 함수스코프고 블록스코프엔 접근할 수 있다.
4에서 let은 블록스코프고 if도 블록스코프이기 때문에 let은 안으로 접근할 수 없다.
//for문
5. var는 접근가능하다
6. let은 블록스코프라서 역시 접근 못한다
문제점
아래 코드를 보면
var로 선언한 for문과 let으로 선언한 for문의 결과가 다르게 나온다.
이는 스코프문제와 closer문제의 결합된 것 이다.
1은 위에 while문과 같이 i는 6으로 나오게 된다.
2번은 0~5로 나온다.
//1
for (var i = 0; i < winBalls.length; i++) {
setTimeout(() => {
console.log(winBalls[i], i);
drawBall(winBalls[i], $result);
}, 1000 * (i + 1));
}
//2
for (let i = 0; i < winBalls.length; i++) {
setTimeout(() => {
console.log(winBalls[i], i);
drawBall(winBalls[i], $result);
}, 1000 * (i + 1));
}
//closer해결을 통한 var사용
for (var i = 0; i < winBalls.length; i++) {
(function(j) {
setTimeout(() => {
console.log(winBalls[j], j);
drawBall(winBalls[j], $result);
}, 1000 * (i + 1));
}) (i);
}
결론:
var가 함수스코프 for에 접근이 가능하며 고정이 안되어서 666666
let은 블록스코프라서 접근이 불가능하고 고정이 되어서 1,2,3,4,5으로 나온다.
=>함수스코프를 가진 variable과 비동기함수인 settimeout이 만나면 클로저 문제가 발생한다.