2022-05-30 호이스팅과 TDZ에 관하여

정종훈·2022년 5월 30일
0

T.I.L

목록 보기
16/20

면접시 대답

자바스크립트에서 호이스팅이란, var 선언문이나 함수 선언문 등 모든 선언문이 해당 스코프의 선두로 옮겨진 것처럼 동작하는 특성을 말합니다.

여기서 var로 선언한 변수의 경우 호이스팅 시 undefined로 변수를 초기화힙니다.

즉, 변수의 선언와 초기화가 동시에 이루어 집니다.

따라서 선언부 위치에 상관없이 참조, 할당이 가능합니다.

그러나

ES6 에서 도입된 let, const로 선언한 변수의 경우 호이스팅 시 변수를 초기화 하지 않습니다.

따라서 실행시점에서 실질적인 선언부를 만날때까지 초기화는 이루어 지지 않으므로

선언부 상단에서는 참조 및 할당이 불가능합니다.

이때, 변수 스코프의 최상단에서 변수의 초기화 완료 시점까지의 간극을 시간상 사각지대 라고 말합니다.

호이스팅에 대한 나의 이야기

a = 2;
var a;
console.log(a); // (1)

(1) 식의 실행결과는 무엇일까? 정상적으로(?) 2가 출력된다.

그렇다면

console.log(a); // (2)
var a = 2; 

(2) 식의 실행결과는 무엇일까? 답은 2가 아니라 undefined이다.

위 두 결과를 모두 맞추었다면 당신은 호이스팅을 어느정도 이해한다고 생각한다

허나, (2)식을 2로 대답한 나는 왜 (2) 식의 답이 undefined가 나오는지 지금부터 기록할 것이다.

누군가는 var = 2 를 하나의 구문으로 볼 수 있겠지만

실제로 자바스크립트는

var a, a = 2 이렇게 두 개의 독립된 구문으로 본다.

(

그럼 여기서 어려운 질문!

  • 그럼 왜 저렇게 두 개의 구문으로 나누어 지는 것일까?

대답은 자바스크립트 엔진은 인터프리팅 하기 전에 그 코드를 먼저 컴파일하기 때문 이라고 할 수 있겠다.

허나 인터프리팅이 뭔지 컴파일이 뭔지는 정확히 머리로 이해되지 않고 지금 주제와 벗어나

나중에 공부하기로 하자.

https://hashcode.co.kr/questions/7560/javascript-자바스크립트는-컴파일언어인가요-인터프리터-언어인가요

)

그래서 실제로 (2) 식은

var a;
console.log(a);
a = 2; 

가 되고 할당이 되기전에 console.log을 찍으므로 undefined가 되는것이다.

여기서 var a 부분이 갑자기 맨 위로 올라가 코드 실행이 되는데

이 과정을 정리하면 변수와 함수 선언문이 선언된 위치에서 해당 스코프의 선두로 ‘옮긴것처럼' 동작하는것을 호이스팅이라고 한다.

참고로 함수 표현식은 끌어올려지지 않는다

자 그런데 돌아와서 (2) 식을 조금 비틀어 보자.

console.log(a); // (3) ReferenceError: Cannot access 'a' before initialization
let a = 2;

(2)식의 내용 중 var 에서 let 으로 바꿨을 뿐인데 왜 레퍼런스 에러가 뜰까?

바로 TDZ 때문이다.

TDZ에 대한 나의 이야기

우선 변수의 생성과정 3단계에 대해 잠깐 이야기 해보자.

  1. 선언단계 : 변수를 실행 컨텍스트의 변수 객체에 등록한다. 이 변수 객체를 스코프가 참조한다.
  2. 초기화단계: 변수 객체에 등록된 변수를 위한 공간을 메모리에 확보한다. 이때 변수는 undefined가 된다.
  3. 할당단계: undefined로 초기화된 변수에 실제 값을 할당한다.

var 는 호이스팅이 발생하면, 선언과 초기화가 동시에 이루어진다.

실행 시점의 스코프 최상단에서 해당 변수에 대한 메모리가 살아있기 때문에 선언부 위치에 상관 없이 참조ㅡ 할당이 가능하다.

그.러.나

let, const 는 호이스팅이 발생하면, 선언만 이루어지고 실행시점에서 실질적인 선언부를 만날 때까지 초기화는 이루어지지 않는다. 이 간극만큼 해당 변수에 대한 메모리는 존재하지 않기 때문에 선언부 상단에서 참조, 할당이 불가능하다.

이때 스코프의 진입지점과 해당 식별자의 실질적 선언부 사이를 일시적 사각지대, TDZ 라고 한다.

{
    // TDZ가 스코프 맨 위에서부터 시작
    const func = () => console.log(letVar); // OK

    // TDZ 안에서 letVar에 접근하면 ReferenceError

    let letVar = 3; // letVar의 TDZ 종료
    func(); // TDZ 밖에서 호출함
}

위 코드가 정상적으로 동작하는 이유는 함수의 호출지점이 사각지대 밖이기 때문이다.

참조:

  • 면접시 대답

https://developer.mozilla.org/ko/docs/Glossary/Hoisting

  • 호이스팅에 대한 나의 이야기

https://meetup.toast.com/posts/86

https://poiemaweb.com/js-data-type-variable#24-변수-호이스팅variable-hoisting

  • TDZ에 대한 나의 이야기

https://tecoble.techcourse.co.kr/post/2021-04-25-hoisting/

https://poiemaweb.com/es6-block-scope#13-호이스팅

https://medium.com/korbit-engineering/let과-const는-호이스팅-될까-72fcf2fac365

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/let#시간상_사각지대

상의할 주제:

const, let 은 호이스팅이 되지 않는가?

profile
괴발개발자에서 개발자로 향해보자

0개의 댓글