본문 바로가기

Dev.FrontEnd/Javascript

[자바스크립트] for vs while 차이점과 closer문제

 

 

 

 

 

목차

     

     

     

     

    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이 만나면 클로저 문제가 발생한다.