호이스팅(Hoisting)

호이스팅(Hoisting)

호이스팅이란 변수 선언문이나 함수 선언문등 모든 선언문이 해당 Scope의 선두로 옮겨진 것처럼 동작하는 특성을 말한다. 즉 선언문은 할당되기 이전에 참조가 가능하다.(undefiend)

변수 자체(변수의 할당된 값)를 끌어올리는게 아니라, 변수의 선언부(선언과 초기화-undefined)만 끌어올린다.

예제)

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

위 코드는 아래처럼 변경된 것처럼 실행된다.

var a; // 변수를 선언만 했기 때문에 a 에는 undefined 값이 들어가 있게 된다.
console.log(a); // 따라서 undefined가 출력된다.

// var 선언은 문서(또는 함수)가 시작될 때 처리되기 때문에
// var 로 선언한 변수는 어디서든지 참조가 가능하다.(전역 변수)
// 다만 변수에 할당이 되기 전까지는 undefined값을 가지고 있다.

a = 5; // 여기서 값이 undefined에서 5로 할당이 이뤄지게 된다.

var a = 5; 라고 선언과 할당를 했다면 var a; 를 끌어올려둔 후(선언과 초기화 까지만) 원래 있던 자리에서 a = 5; 로 할당이 이뤄진다.

선언은 호이스팅 되지만 할당은 호이스팅 되지 않는다.(참고)

modern(현대의) javascript 에서는 var를 쓰지 말아야 한다. 이것은 legacy(오래전의) javascript 에서만 볼 수 있는 변수 키워드이다. 모던한 javascript 에서는 const, let만 사용하고, 호이스팅의 TDZ(Temporal Dead Zone - 일시적인 사각 지대)을 조심하라.

TDZ(Temporal Dead Zone - 일시적 사각 지대)

const test = 'test';
function a() {
    console.log(test);
    let test = 5;
}
a();

이런 코드가 있다. 실행하면 ReferenceError: Cannot access 'test' before initialization 에러를 마주하게 된다. 즉 test 변수를 초기화 하지 않았기 때문에 접근할 수 없단다.

  • 호이스팅이 일어나지 않는다면 함수 안에서 console.log(test); 부분에 test 라고 찍혀야 정상이다.

  • 호이스팅이 일어났다면 당연히 undefined가 찍혀야 정상일테다.

      const test = 'test';
      function a() {
          let test; // undefined
          console.log(test);
          test = 5;
      }
      a();

호이스팅과 TDZ

TDZ는 변수의 선언부터 변수에 할당되는 부분을 만나기 전까지 형성되는 구간이다.(참고)

const test = 'test';
function a() {
    let test; // 호이스팅에 의한 변수 선언
    // 변수가 선은은 되었지만 아직 초기화 구문을 만나지 못했다.
    // 즉 아래 tset = 5; 로 할당이 이뤄지기 전까지 TDZ가 형성되게 된다.
    // 따라서 여기에서 오류가 발생하게 된다.
    console.log(test);
    test = 5; // 변수의 할당
}
a();

정리(2020.03.26 추가)

var 키워드의 경우 선언(Variable Object 에 등록)과 초기화가 동시에 일어난다. 여기서 초기화란 메모리에 공간을 확보하고 undefined 값으로 할당하는 과정까지이다.

하지만 let, const 키워드는 선언과 초기화가 분리되어 일어난다. 즉 선언을 하면 Variable Object에 등록은 되지만 실제 초기화는 선언문이 있는 곳에서 일어나게 된다. 여기에서 TDZ가 일어나게 되는 것이다.

정리 2 - 함수 호이스팅의 경우

함수 선언문의 경우

함수 선언문으로 정의된 함수는 자바스크립트 엔진이 스크립트가 로딩되는 시점에 바로 초기화를 하고 이를 VO(variable object)에 저장한다. 즉 함수 선언, 초기화, 할당이 한 번에 이뤄진다.(이것이 변수와는 다른 점이네.) 그렇기 때문에 함수 선언의 위치와는 관계없이 소스 내 어느 곳에서든 호출이 가능하다.

let res = square(5);

function square(number) {
    return number * number;
}

함수 표현식의 경우

함수 표현식은 함수를 변수에 저장하기 때문에 변수 호이스팅이 발생한다. 이는 위 정리 1번을 보면 된다.

자바스크립트의 권위자인 더글러스 크락포드는 호이스팅 같은 문제로 인해 함수 선언식 보다는 함수 표현식만을 사용할 것을 권고한다고 한다.
함수 호이스팅이 함수 호출 전 반드시 함수를 선언하여야 한다는 규칙을 무시하므로 코드의 구조를 엉성하게 만들 수 있다고 지적했다.

함수 선언문으로 함수를 정의하면 사용하기에 쉽지만 대규모 애플리케이션을 개발하는 경우 인터프리터가 너무 많은 코드를 변수 객체(VO)에 저장하므로 애플리케이션의 응답속도는 현저히 떨어질 수 있으므로 주의해야 할 필요가 있다.

결론

변수, 함수, 클래스 등은 사용하기 전에 필히 정의하고 할당한 후 사용하자.

참고자료

'TIL' 카테고리의 다른 글

[tailwindcss]폰트 클래스 삽입  (3) 2020.05.25
객체 순회/배열 순회  (0) 2020.03.27
자바스크립트 예약어  (0) 2020.03.27
mongodb - projection  (0) 2020.03.20
[TIL]2020.03.06  (0) 2020.03.06

+ Recent posts