Menu

메모용 개발 블로그

전체보기 > Develop > JavaScript >

자바스크립트의 호이스팅

2023-04-27 17:27:49

호이스팅이란?

자바스크립트의 변수 혹은 함수의 선언이 위로 올려지는 특징이 있습니다. 이를 호이스팅이라고 합니다.

호이스팅의 동작

자바스크립트는 많은 언어들 처럼 무언가를 호출하면 이를 콜 스택에 올리고 실행하면 꺼내는 식으로 동작합니다.

간략하게 이야기하면 이때 올라가는 객체가 실행 컨텍스트이며, 내부에 전역 혹은 함수가 실행(ES6 이후로는 블록도 포함)될 때마다 이 실행 컨텍스트가 콜 스택에 올라갑니다. 이 실행 컨텍스트 내부에는 매개변수, 변수, 함수 등을 정보 등이 함께 들어있습니다.

즉, 사용되는 변수나 함수 정보를 미리 알고 있게되므로 호이스팅이 동작하게 되는 것 입니다. 이를 간단하고 이해하기 쉽게 표현 하는 것이 '선언이 위로 끌어올려진다.'인 셈 입니다.

호이스팅의 이유

자바스크립트를 보다 쉽게 사용하기 위해서라고 합니다.

아무래도 '함수의 사용보다 선언이 앞에 있어야 한다.'라는 규칙은 가볍게 사용하는 언어에 어려운 규칙이라 생각한 모양입니다.

덕에 메인으로 동작하는 스크립트를 위에 위치하고 세세한 함수들을 밑으로 몰아넣어 관리할 수도 있게 되며, 각 함수간에 순서를 신경안쓰고 유사기능끼리 아무 순서로 묶어도 상관없게 됩니다.

함수 호이스팅 예시

printHelloWorld();

function printHelloWorld() {
    console.log("Hello World!!!");
}

분명히 함수의 선언은 뒤에 작성했으나, 아래와 같이 함수 호출이 정상적으로 됩니다.

실행결과

Hello World!!!

변수 호이스팅 예시

console.log(a);
var a = "Variable";
console.log(a);

변수의 경우도 마찬가지로 선언은 뒤에 작성하였으나, 별다른 오류가 없습니다

실행결과

undefined
Variable

실행 결과를 보면 변수의 호이스팅이 일어나고 값을 undefined로 초기화해버린다는 것을 확인할 수 있습니다.

호이스팅의 문제점

꼭 호이스팅 이야기와 함께 따라오는 것이 let, const 같은 것을 써라! 입니다.

사실 var를 써도 문제가 생기는 일은 드뭅니다. 전역 변수를 남발하는 것 자체를 권장하지 않기도 하니 대충 지켜서 짜면 별 문제가 안생기나 가끔은 이런 문제가 생길 수 있습니다.

var a = 5;

function func() {
    console.log(a);

    var a = 3;
}

func();

위 코드를 호이스팅을 모르는 누군가가 본다고 하면 당연히 5가 출력되리라 기대합니다.

하지만 호이스팅에 의해 다음과 같은 결과가 나타납니다.

undefined

이 문제점을 풀이를 해봅시다.

우선 var로 선언한 변수는 함수 단위로 스코프를 가진다는 사실을 알고 가면,

처음 1행에 선언한 변수 a는 전역 스코프에 초기화가 되었습니다.

이후 함수에 들어가보면 아래 존재하는 var a = 3이라는 함수 단위 스코프의 변수 a가 선언되어 있습니다.

변수의 선언이므로 호이스팅이 발생하여 선언은 함수의 최상단으로 끌어올려지고 undefined로 초기화 됩니다.

직관적인 코드로 풀어보면 다음과 같습니다.

var a = 5;

function func() {
    var a = undefined;
    console.log(a);

    a = 3;
}

a();

let, const

let, const를 사용하라 한다면 위와 같은 문제점이 해결된 상태일 것 입니다.

간혹 let, const는 호이스팅이 발생하지 않는다는 이야기를 하는데. 이는 틀렸습니다.

이 글의 앞부분인 [호이스팅의 동작](#호이스팅의 동작) 부분을 굳이 작성한 이유이기도 합니다.

실행 컨텍스트의 구성에 '변수'의 정보가 들어가는데 let, const역시 변수이므로 동일하게 동작합니다.

그러므로 let, const 역시 호이스팅이 발생하나, var과 달리 undefined로 초기화 되는 일이 발생하지 않습니다.

그렇기에 선언 이전에 변수를 참조하면 오류가 발생합니다.

시간상 사각지대(Temporal Dead Zone)

TDZ라고 줄이기도 하는 시간상 사각지대는 해당 변수가 초기화 되기 이전 시점까지를 말합니다.

이 시점에 해당 변수에 접근하려하면 오류를 발생시킵니다.

예시 1

console.log(a);

let a = 5;

결과

ReferenceError: Cannot access 'a' before initialization

이러한 특성으로 호이스팅에 의한 문제가 발생하지 않으며, 사용 전 선언이라는 명확한 규칙을 적용할 수 있어 letconst를 사용하라고 하는 것 입니다.