[JS] Variable Environment & Hoisting & TDZ

JunSeok·2023년 12월 8일
0

Javascript

목록 보기
7/16

Hoisting

호이스팅은 일부 타입의 변수를 실제로 선언되기 전에 코드 내에서 접근 또는 사용가능하게 하는 것을 의미한다.
표면상으로는 특정 변수를 해당 scope의 꼭대기로 올리는 것처럼 보이지만 실제 동작 원리는 다음과 같다.

자바스크립트 엔진은 코드를 실행하기 전에 변수 선언을 스캔하는데,
이 작업은 execution context의 creation phase에서 이루어지며,
이 단계에서 코드 내에 선언된 모든 변수와 함수가 variable environment object에 저장된다.
execution context and call stack 포스팅

Hoisting이 적용되는 타입

호이스팅은 모든 변수 타입에 똑같이 작동하지 않는다.
여기서 말하는 변수에는 함수도 포함된다.
하지만 함수 선언식은 제외한다. 함수를 변수에 저장하는 것이 아니기 때문이다.
따라서 함수를 선언전에 사용하고 싶으면 함수 선언식을 사용하면 되고, 이를 제외한 함수 표현식과 화살표 함수의 호이스팅 여부는 변수 선언 키워드에 따라 달라진다.

Function declaration

  • 호이스팅 된다.

var

  • var로 선언된 변수는 호이스팅되기는 하지만 초기값은 undefined이다.
  • 이는 일종의 버그이며 요즘 var를 거의 안쓰는 주된 이유 중 하나이다.

let, const

  • letconst는 호이스팅되지 않는다.
  • 정확히 말하자면, 기술적으로는 호이스팅이 되었지만 값은 기본적으로 uninitialized로 설정되어 있다. 아예 초기화가 안 된 것이다.
  • 그래서 선언전에 사용이 불가능하며, 호이스팅이 안 된 것처럼 보인다.
  • 이 말을 이해하려면 TDZ(Temporal Dead Zone) 이라는 개념을 이해해야 한다.

TDZ(Temporal Dead Zone, 사각지대)

TDZ는 해당 변수의 scope 시작부분과 해당 변수 선언 라인 사이의 공간을 의미한다.

자바스크립트 엔진은 코드를 실행하기 전에 이미 코드를 읽었기 때문에 job 변수가 초기화될 것이라는 것을 이미 알고 있다.
그래서 const로 선언된 job변수를 variable environment에 uninitialized 상태로 설정해놓았다.
코드가 실행되고 변수가 선언된 라인에 도달하면 TDZ에서 벗어나job변수를 사용할 수 있게 된다.
즉 엔진은 이미 job 변수의 존재를 알고 있지만 변수 선언 라인(초기화) 이후 즉 TDZ 이후에 접근할 수 있다고 알려준다.

에러 메시지를 통해 기술적으로는 호이스팅되었지만 사용은 불가능하다 라는 말을 이해할 수 있다.
변수 x처럼 아예 선언이 되지 않았다면 ReferenceError: x is not defined라는 에러가 발생하지만,
const로 선언된 변수가 아직 TDZ에 있는데 사용하려 하면 ReferenceError: Cannot access 'job' before initialization이라는 에러가 발생한다.

요약하면 다음과 같다.

let이나 const로 선언된 모든 변수는 scope의 시작부터 변수 선언 라인까지의 TDZ를 갖는다.
그렇게 선언된 변수는 TDZ 이후에만 안전하게 사용가능하다.

TDZ가 필요한 이유

TDZ는 let, const와 함께 ES6에서 등장한 개념이다.
그렇다면 왜 등장하게 되었을까.

  • 앞서 설명한 TDZ와 함께하는 코드 실행동작이 에러를 피하고 캐치하는데 훨씬 용이하기 때문이다.
    왜냐하면 실제로 선언되기 전에 선언되지 않은 변수를 사용하면 심각한 버그를 야기할 수 있기 떄문이다.
  • const로 선언된 변수가 제대로 동작하게 하기 위함이다.
    ES6 이전에 존재한 var 키워드로 선언된 변수는 선언 전에 undefined로 초기화가 되고 나중에 진짜 value를 할당된다.
    하지만 const 변수는 재할당이 불가능하기 때문에 이러한 동작 자체가 불가능하다.
    그래서 처음에 uninitialized 상태로 두었다가 실제로 선언에 도달했을 때만 할당하는 것이다.

결론

  • 변수 선언할 때 var 키워드 사용하지 말 것.
  • 대부분의 경우 const 사용하고, 필요시 let 쓸 것.
  • 클린 코드를 위해 각 scope의 상단에 변수 선언할 것.
  • 항상 모든 함수를 먼저 선언하고 선언 후에만 사용할 것.

참조

https://developer.mozilla.org/en-US/docs/Glossary/Hoisting
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#temporal_dead_zone_tdz
https://www.udemy.com/course/the-complete-javascript-course/

profile
최선을 다한다는 것은 할 수 있는 한 가장 핵심을 향한다는 것

0개의 댓글