글 작성자: 망고좋아
반응형

🎯 호이스팅, Hoisting

📝 코드 실행 시 변수 처리

  • JS 엔진이 코드를 읽으면 생성 단계에서 실행 컨텍스트 생성
    • 함수 선언문은 실행 단계에서 함수 전체가 실행 컨텍스트에 저장
  • var 변수는 저장 시 undefined로 초기화
  • let, const는 초기화되지 않는다. 그냥 존재만 알고 있는 상태
    • 초기화되지 않았기 때문에 접근하면 에러 발생

 

📝 코드로 알아보는 호이스팅

console.log(callMe()); // undefined

var x = 10;

console.log(callMe()); // 10

function callMe() {
    return x;
}
  • 호이스팅은 변수가 선언됨 시점보다 앞에서 사용되는 현상이다.
  • 이는 var 변수가 생성 단계에서 undefined로 초기화되는 것이 원인이다.
  • 함수는 생성 단계에서 함수 전체가 저장되므로 뒤에서 선언되어도 호출이 가능하다.
// error: Uncaught ReferenceError: Cannot access 'x' before initialization
console.log(callMe());

let x = 10;

console.log(callMe()); // 10

function callMe() {
    return x;
}
  • let, const 변수는 생성 단계에서 초기화되지 않는다.
  • 선언문 이전에 접근 시 ReferenceErrorr가 발생한다.
  • 이 경계를 Temporal Dead Zone(TDZ)라 한다.
  • 따라서 let, const는 hoisting이 발생하지 않는다.
    • x의 값이 초기화되지 않았기 때문에 접근하면 에러가 난다.

 

📝 var, let, const 

  • var, let, const 모두 변수를 선언하는 키워드이다.
  • var, let은 변수에 재할당이 가능하지만, const는 재할당이 불가능하다.
  • var는 함수 레벨 스코프, let과 const는 블록 레벨 스코프 변수이다.
function varFor() {
    for (var i = 0; i < 3; ++i) {
        setTimeout(() => {
            console.log("i: ", i);
        }, 0);
    }
}
function letFor() {
    for (let i = 0; i < 3; ++i) {
        setTimeout(() => {
            console.log("i: ", i);
        }, 0);
    }
}

varFor(); // 3 3 3
letFor(); // 0 1 2
  • varFor에서 i는 varFor 함수 번위에 존재하는 변수이다.
  • 따라서 setTimeout이 호출될 때 i는 for블록이 끝난 시점에 소멸하지 않는다.
  • letFor에서 i는 for블록 안에 존재하는 변수이다.
  • 각 for 블록이 실행되고 i는 소멸한다. 다만, 이 경우 각 화살표 함수의 closure에 저장된다.

 

📝 좀 더 알아보는 for문 안에 setTimeout을 사용할 때 var와 let의 차이점

  • var는 함수 레벨 스코프
  • let은 블록 레벨 스코프
    • 블록은 if문, for문 while문 등으로 중괄호로 묶은 부분을 의미
function varFor() {
    for (var i = 0; i < 3; ++i) {
        console.log(i);
        setTimeout(() => {
            console.log("i: ", i);
        }, 0);
    }
}

varFor();
/* 
출력 결과
0
1
2
i: 3
i: 3
i: 3
*/

var의 문제점

  • for문 안에 setTimeout을 사용하면 클로저 문제가 발생된다.
  • for문을 다 돌고 난 뒤 setTimeout이 실행된다. ⇒ 비동기 관련 문제
  • for문은 속도가 빨라서 1초보다 훨씬 짧은 시간에 다음 i로 넘어가게 되어서 또다시 setTimeout을 실행한다. 이렇게 짧은 시간 안에 0~2까지 3번의 setTimeout이 실행된다.
  • 즉, for문이 시작되고 나서 setTimeout의 콜백 함수는 모든 함수가 종료되고 난 뒤 실행된다. 따라서 setTimeout은 이미 값이 변경된 i를 볼 수밖에 없다. 따라서 3을 3번 반복해서 출력한다.
  • 즉시 실행 컨텍스트로 문제를 해결할 수 있다. 또는 let을 사용

 

📌 참고

반응형