• 참조

    • 블로그: https://velog.io/@rkio/Javascript-호이스팅hoisting에-대하여
  • 호이스팅이란

    • JavaScript에서 호이스팅이란 인터프리터가 변수와 함수의 메모리 공간을 선언 전에 미리 할당하는 것을 의미
    • 변수와 함수의 선언부가 현재 스코프 최상단 영역으로 옮겨지는 것처럼 보이는 현상
  • Lexical Environment

    Lexical Environment의 대략적인 구조

    Lexical Environment의 대략적인 구조

    • identifier-variable 매핑 정보를 가지고 있는 데이터 구조
    • 컴파일 단계에서 코드가 실행되기 몇 마이크로 초 전, 함수와 변수의 선언이 스캔됨
    • 스캔된 모든 함수, 변수의 선언은 Lexical Environment라고 불리는 JavaScript 데이터 구조 내 메모리에 추가
    • 즉 함수, 변수가 코드내에서 선언되기 전에 사용할 수 있음
  • 호이스팅의 예시

    • 함수 선언식의 호이스팅

      // 아래 예시처럼 선언부가 사용부보다 밑에 있지만 정상적인 접근 가능
      helloWorld();
      
      function helloWorld() {
      	console.log("Hello World");
      }
      
      // 위 코드가 실행되는 과정에서 Lexical Environment의 상황
      // 아래처럼 메모리에 매핑되어 접근 가능
      LexicalEnvironment = {
      	helloWorld: <function object>
      }
      
    • 함수 표현식의 호이스팅

      // 아래처럼 함수를 선언하지 않고 표현식을 사용하는 경우 접근 불가능
      // 함수 표현식을 사용하는 경우 함수 표현식이 먼저 작성되어야 접근 가능
      helloWorld();  // TypeError: helloWorld is not a function
      
      // let, const로 선언하는 경우 에러 내용이 달라짐
      // var -> TypeError: helloWorld is not a function(undefined로 초기화)
      // let, const -> ReferenceError: Cannot access 'helloWorld' before initialization
      var helloWorld = function() {
      	console.log("Hello World");
      }
      
    • 함수 선언식/표현식에 따라 달라지는 이유

      • JavaScript에서는 오직 선언만을 호이스팅하는 것이며 초기화를 할당하는 것이 아님
      • 즉 표현식을 사용하는 경우 변수에 대한 초기화에 해당하므로 호이스팅이 이뤄지지 않는 것처럼 보임
    • 호이스팅이 이뤄지는 과정

      • var

        • var로 변수는 호이스팅이 이뤄지지 않음

        • 정확히는 선언은 호이스팅되지만 초기화를 할당하지 않음

        • 컴파일 단계에서 var 변수 선언을 찾아 LexicalEnvironment에 저장하고 undefined로 초기화를 수행

        • 이후 코드를 실행하는 과정에서 할당하는 코드에 도달했을 때 JavaScript엔진은 변수에 값을 할당

        • 예시 코드

          // var 변수의 사용
          console.log(a); // undefined
          
          var a = 3;
          
          // var 변수를 사용하는 경우의 Lexical Environment
          LexicalEnvironment = {
          	a: undefined
          }
          // 이후 코드 실행을 위해 JavaScritp엔진이 할당 코드에 도달한 경우
          LexicalEnvironment = {
          	a: 3
          }
          
          // 아래는 과정을 코드로 나타낸다면
          var a;
          
          console.log(a);
          
          a = 3;
          
      • let, const

        • let, const에서는 var과는 다르게 동작

        • let, const에서는 uninitialized로 LexicalEnvironment에 저장

        • 즉 let, const는 호이스팅이 이뤄지지 않는 다는 말이 있는데, 정확히는 호이스팅은 되지만 undefined로 초기화되지 않고 uninitialized로 남아있음

        • let, const의 초기화는 오직 JavaScript 엔진이 작동할 때 LexicalBinding이 발생할 때 이루어지며 그전까지는 해당 변수에 접근할 수 없도록 한 것

        • 또한 JavaScript엔진이 작동하기 전까지 접근할 수 없는 시간을 **TDZ(Temporal-Dead-Zone)**라고 함

        • 만약 LexicalBinding에서 let, const 초기화 값을 찾지 못한 경우 undefined로 초기화되거나 const의 경우 에러를 발생(const의 경우 선언과 동시에 초기화가 이뤄져야 함)

        • 예시 코드

          let a;
          console.log(a); // undefined
          a = 3;
          
          const a;
          console.log(a); // SyntaxError: Missing initializer in const declaration
          a = 3;
          
      • class

        • let, const와 같이 선언 코드를 만나기 전까지는 uninitialized 상태

        • 즉, TDZ의 영향을 받음

        • 예시 코드

          let peter = new Person("Perter", 25); // ReferenceError: Cannot access 'Person' before initialization
          
          console.log(peter);
          
          class Person {
          	consturctor(name, age) {
          		this.name = name;
          		this.age = age;
          	}
          }