본문 바로가기
엘리스 AI 트랙 4기/elice AI track

[3주차] 자바스크립트 엔진과 Hoisting

by _sweep 2022. 1. 29.

1월 29일 자 학습 내용 정리입니다.

 

 

 자바스크립트 엔진

자바스크립트 엔진은 자바스크립트 코드를 읽어 실행하는 프로그램이다.

작성한 자바스크립트 코드는 자바스크립트 엔진을 통해 파싱되고 실행된다.

 

자바스크립트 엔진은 코드를 실행하기 전 실행 컨텍스트를 생성한다.

실행 컨텍스트는 두 단계를 통해 생성되는데 바로 생성 단계와 실행 단계이다.

생성 단계에서는 엔진이 변수 선언을 읽고 실행 단계에서는 엔진이 변수 값을 할당한다.

 

✔️ 생성 단계

자바스크립트 엔진은 생성 단계에서 함수 선언문, 함수 표현식, 변수 등을 읽어 실행 컨텍스트에 저장한다.

함수 선언문의 경우 함수 명과 함수 전체가 저장되지만 함수 선언문 외의 변수의 경우 값이 저장되지는 않고 실행 컨텍스트의 렉시컬 환경을 구성한다.

 

함수의 렉시컬 환경(Lexical Environment)은 함수가 사용하는 변수들을 둘러싼 환경을 의미한다.

특정 변수의 값은 함수의 렉시컬 환경 안에서 찾을 수 있다.

렉시컬 환경은 실행 컨텍스트 안에 정의된 Variable Object라고 생각하면 된다.

 

✔️ 실행 단계

변수에 값을 할당하는 구문을 만나면 실행 컨텍스트에 값을 저장한다.
그 외 코드를 한줄씩 읽어나가며 실행한다.

 

 

Hoisting

호이스팅(Hoisting)은 변수가 선언된 시점보다 앞에서 사용되는 현상이다.

생성 단계에서 실행 컨텍스트가 생성되고 이때 함수 선언문은 함수명과 함수 전체가 저장되는데 함수 안의 변수들이 어떤 키워드로 선언되었는지에 따라 초기화가 달리 진행된다.

 

let과 const 변수는 생성단계에서 초기화되지 않지만 var 변수는 undefined라는 값으로 초기화된다.

즉, Hoisting의 원인은 var 변수가 생성 단계에서 undefined로 초기화 되기 때문이다.

 

 

위의 사진 속 코드에서는 c가 30이라는 값을 갖는다고 선언되기 이전에 콘솔 로그로 c에 접근하고 있는 Hoisting이 일어나고 있다.

하지만 c가 var 키워드로 선언되었기 때문에 에러가 나는 것이 아닌 undefined라는 값을 얻는다.

 

 

반면 let과 const 변수는 생성단계에서 초기화되지 않고 uninitialized 상태로 남는다.

따라서 선언하기 이전에 접근하는 Hoisting이 일어났을 때 Reference Error가 발생한다.

이 경계를 Temporal Dead Zone(TDZ)라고 한다.

 

정확하게 말하자면 let과 const가 Hoisting이 발생하지 않는 것은 아니다.

앞서 말했듯이 위의 사진만 봐도 변수를 선언된 시점보다 앞에서 사용하는 것 자체는 가능하기 때문이다.

다만 let과 const는 초기화되지 않아 에러가 발생할 뿐이다.

 

 

✅ var와 let, const

var, let, const는 모두 변수를 선언하는 키워드이다.

var, let은 변수에 재할당이 가능하지만 const는 재할당이 불가능하다.

var는 함수 스코프, let과 const는 블록 스코프 변수이다.

 

✔️ var

function test() {
    for (var i = 0; i < 3; ++i) {
        setTimeout(() => console.log("i: ", i), 0);
    }
}
test();

// output
// i: 3
// i: 3
// i: 3

 

var는 함수 스코프이기 때문에 var i로 for문을 돌았다면 var 키워드로 선언된 i는 for문이 끝나면 소멸하는 것이 아니라 함수 안에 살아있다.

따라서 i는 최종값인 3으로 저장되고 i의 값이 3인 것만 콘솔 로그로 출력된다.

 

 

✔️ let, const

function test() {
    for (let i = 0; i < 3; ++i) {
        setTimeout(() => console.log("i: ", i), 0);
    }
}
test();

// output
// i: 0
// i: 1
// i: 2

 

let과 const는 블록 스코프이다.

let i로 선언했다면 for문 블럭 안에서만 존재하게 되어 for문이 끝나면 i는 소멸한다.
다만 이 경우 화살표 함수의 closure에 저장된다.

따라서 콘솔 로그 실행 시 closure에 접근해 i의 변화된 값을 확인할 수 있다.

 

 

 

 

 

 

댓글