Javascript 호이스팅과 TDZ 이해하기

고광필·2022년 3월 1일
0

Front

목록 보기
5/33

어떤 기업의 면접 후기 글을 읽다가 js관련 질문이 햇갈려서 관련 개념을 다시 익히느라 늦게 돌아왔습니다.

  var obj = {
    name: "B",
    print: function () {
      var inner1 = function () {
        console.log(this.name, name);
      };
      inner1();

      var inner2 = () => {
        console.log(this.name, name);
      };
      inner2();

      var name = "C";
      console.log(window.name, this.name, name);
    },
  };

  name = "A";
  obj.print();

위 문제였는데요. 정답을 모르겠어서 관련된 내용으로 제가 햇갈려 한 내용들을 다시금 정리했습니다.

내가 햇갈리는 것

  1. print() 안에서 name이 가지는 값을 잘 모르겠다. 오류가 나야할것 같은데?
    => 이번 포스팅에서 이 부분을 이해하기위해 공부한 내용들을 정리하겠습니다.

  2. this가 무엇을 의미해서 this.name이 달라지는지 모르겠다.
    => 이건 다음 포스팅에서 정리합니다.

const와 let의 배경, 호이스팅

ES6에서 const와 let이 추가되었습니다.
원래 사용하던 var 키워드가 있었는데 새로운 키워드가 추가된 이유가 무엇일까요?
맨 위 코드에서 name이 가지는 값과는 어떤 연관이 있을까요?

기존 var 키워드의 동작 방식

console.log(num); // undefined
var num = 3;
console.log(num); // 3

위 코드는 변수를 선언하기 전에 사용하고, 변수를 선언합니다.
하지만 코드의 문제가 없습니다.

호이스팅

호이스팅은 쉽게 말해 코드를 끌어올려서 먼저 실행했다는 뜻입니다.
자바스크립트 엔진이 블록의 최상단으로 코드를 끌어올린것입니다.

좀 더 정확히 말하자면 변수의 선언과 초기화를 나누어서 먼저 선언만 해놓습니다.
따라서 위의 코드는 num이라는 변수를 맨 위로 끌어올려서 선언만 먼저 합니다.
이후 초기화문을 만났을 때 선언된 num 변수에 3이라는 값이 들어갑니다.
그래서 출력이 undefined와 3이 나옵니다.

var키워드 외에도 function 함수가 호이스팅됩니다.

그럼 const와 let은 호이스팅이 안되나?

var와 호이스팅을 세트처럼 얘기하듯이
const와 let은 TDZ라는 세트가 있습니다.

위에서 var 호이스팅은 함수의 선언과 초기화를 나누어서, 먼저 선언만 한다고 했습니다.
console.log에 undefined가 나오는것으로 확인했죠?

const와 let도 호이스팅이 되어 먼저 선언이 되고, 초기화문을 만났을 때 값이 초기화됩니다.
그러나, 초기화 전까지 변수에 접근하는것이 막혀있습니다.
이를 TDZ라고 합니다.

TDZ

Temporal Dead Zone
const, let 키워드로 선언한 변수가 호이스팅되어 먼저 선언만 되고, 값이 초기화되기 전까지 접근을 막는 영역을 뜻합니다.

'const, let은 호이스팅되어 선언만 되고 초기화되기 전까지 TDZ에 위치하기 때문에 접근이 불가능하다'고 말할 수 있습니다.

근데 왜 TDZ로 막은것인지?

var 키워드로 선언한 변수는 선언 전에 변수에 접근할 수 있습니다.
버그를 줄이기 위해서는 코드가 어떻게 흘러가는지, 변수가 어떻게 바뀌는지 예측할 수 있어야 합니다.
따라서 변수 선언 전에 TDZ에 위치해서 접근이 불가능하도록 한 const와 let이 등장했습니다.

코드 예시로 보는 호이스팅

  test1();
  function test1() {
    console.log("test1");
  }
  1. function 키워드로 선언한 함수 test1은 호이스팅되어 선언 전에 사용해도 정상적으로 작동합니다.
  console.log(test2); // undefined
  test2(); // test2 is not a function
  var test2 = () => {
    console.log("test2");
  };
  1. undefined와 test2 is not a function 오류가 발생합니다.
    이는 var 키워드로 선언한 변수 test2가 호이스팅되어 먼저 선언만 되었고, 초기화는 되지 않아서 undefined상태임을 보여줍니다.

또한 초기화 전까지는 함수가 아니기 때문에 is not a function 에러가 발생합니다.
그럼 1번과 2번의 차이는 무엇일까요?

함수선언식과 함수표현식의 차이

함수 선언식은 만들어질때부터 함수입니다. 선언과 초기화 모두 호이스팅됩니다.
함수 표현식은 변수로 태어나 변수의 값에 함수의 주소값을 저장하여 함수가 됩니다. 선언만 호이스팅되고, 초기화될 때 함수가 됩니다.

따라서 함수 선언식 test1은 선언+초기화 둘다 호이스팅되어서 미리 사용할 수 있고,
표현식 test2는 var 키워드로 선언 호이스팅되었고, 초기화전에 접근 가능하여 undefined가 나옵니다.

  test3();
  const test3 = () => {
    console.log("test3");
  };
  1. const로 선언한 변수 test3에는 함수가 들어가있습니다.
    test3는 선언 전에 접근하려고 했다는 오류 메시지가 발생합니다.
    const로 선언했기 때문에 호이스팅되어 선언만 먼저 되었고, 값이 초기화되기 전까지 TDZ에 위치해있어 접근이 불가능합니다.

결론

맨 위 코드에서 name이 가지는 값을 제대로 이해하기 위해서
호이스팅, var와 const와 let의 차이, TDZ에 대해 공부했습니다.

  var obj = {
    name: "B",
    print: function () {
      // 여기에 var name; 호이스팅 되어 선언만 됨
      var inner1 = function () {
        console.log(this.name, name);
      };
      inner1();

      var inner2 = () => {
        console.log(this.name, name);
      };
      inner2();

      var name = "C"; // 값이 C로 초기화
      console.log(window.name, this.name, name);
    },
  };

  name = "A";
  obj.print();

또한 위 코드에서 print function 안에 var name가 선언되었기 때문에
해당 블록 print() 안에서 최상단에 호이스팅되어 선언되었고, 그래서 name은 undefined가 나옵니다.
이후 초기화문을 만나고 나서야 C가 출력되는 것을 이해했습니다.

정리

  • 호이스팅은 선언만 먼저 끌어올려서 하고, 초기화는 추후에 하는 동작입니다.
  • var 키워드는 호이스팅되어 선언되고, 초기화 되기 전까지 undefined의 값을 가집니다. 이 때 변수에 접근이 가능합니다.
  • const와 let은 var과 차이점으로 값이 초기화 되기 전까지 접근을 막는 TDZ에 위치해 있습니다.

참고

https://developer.mozilla.org/ko/docs/Glossary/Hoisting
https://poiemaweb.com/js-scope

profile
이해하는 개발자를 희망하는 고광필입니다.

0개의 댓글