호이스팅(Hoisting)

- 자바스크립트를 공부하면서 var, let, const로 선언된 변수들을 한 번 쯤은 보셨을 거에요! 이것들의 차이를 잘 말할 줄 아는 개발자가 되기 위해서는 호이스팅(Hoisting)에 대해 꼭 알고 있어야 해요.

- 이것은 실행 컨텍스트와도 깊은 연관이 있어요. 이 페이지에서는 호이스팅(Hoisting)이 무엇인지, 어떻게 적용되고 있는지 전반적으로 이해 하는 것을 목표로 두도록 해요!

hero

호이스팅이란?

호이스팅의 의미 자체는 코드에 선언된 변수 및 함수를 코드의 상단으로 끌어올려, 해당 변수 및 함수 유효범위의 최상단에 선언하는 것으로 정의되고 있어요.

자바스크립트에서 소스 코드를 실행하는 과정은 생성 단계, 실행 단계로 구분할 수 있어요.

  • 생성 단계

    - 코드를 순차적으로 실행하기 전, 실행 컨텍스트를 생성하면서 여러 식별자들을 스캔하며 준비하는 단계

  • 실행 단계

    - 스캔 후, 선언문 외의 나머지 코드를 순차적으로 실행하는 단계

자바스크립트 엔진은 코드를 실행하기 전에 함수 안을 훑으면서, 실행 가능한 코드를 형상화하고 구분하는 과정을 거쳐요. 이것은 실행 컨텍스트를 위한 과정이에요

이 실행 컨텍스트를 위한 과정에서 발생하는 것이 호이스팅이에요. 즉, 위에서 언급한 생성 단계에서 스코프 안에 존재하는 선언된 식별자들에 대한 정보를 기억하기 위해, 아래쪽에 존재하는 내용 중 필요한 변수와 함수의 선언을 스코프 범위의 최상단으로 내부적으로 끌어올려 처리하는 것이 바로 호이스팅이라고 볼 수 있어요.

스코프 상단에 선언부들이 내부적으로 끌어올려지는 것이기 때문에, 자바스크립트의 모든 선언에는 호이스팅이 일어난다고 볼 수 있어요.

var 변수 선언과 함수 선언문은 호이스팅이 정상적으로 동작하는 것으로 보이지만, let, const, class를 이용한 선언문은 호이스팅이 발생하지 않는 것처럼 동작해요. 이것들을 이제 천천히 살펴보도록 해요.

변수 호이스팅 (var)

var 키워드로 선언된 변수를 호이스팅하는 경우, 자바스크립트 엔진은 선언과 함께 undefined로 변수를 초기화해, 메모리에 저장해요.

변수는 3단계에 걸쳐 생성되는데, var 키워드로 생성된 변수는 선언과 초기화 단계가 함께 일어나요. 즉, 스코프에 변수를 등록(선언 단계)하고 메모리에 변수를 위한 공간을 확보한 후, undefined로 초기화하는 과정이 함께 일어난다는 뜻이에요.

따라서 선언문 이전에 해당 변수에 접근하더라도, 스코프에 호이스팅된 변수가 존재하기 때문에 에러가 발생하지 않아요. 초기화과정에서 저장한 undefined를 반환하기 때문이에요. 이후 변수 할당문에 도달하면 해당 변수에는 비로소 값이 할당되요.

아래는 변수 생성단계에 대한 내용이에요. 읽어보고 넘어가도록 해요.

  • 선언 단계

    - 변수를 실행 컨텍스트에 등록해, 자바스크립트 엔진에 변수의 존재를 알리는 단계

    - 이 변수 객체는 스코프가 참조하는 대상이 되요.

  • 초기화 단계

    - 변수 객체에 등록된 변수를 위한 공간을 메모리에 확보하는 단계

    - 이 단계에서 변수는 undefined로 초기화되요.

  • 할당 단계

    - undefined로 초기화된 변수에 실제 값을 할당하는 단계

console.log(name_1); // 출력 결과는 무엇일까?
var name_1 = "Alice";
↓ ↓ ↓ (자바스크립트 엔진 내부에서 처리되는 결과)
// 호이스팅: 선언문이 유효범위의 최상단으로 올라옴
var name_1 = undefined;
console.log(name_1); // undefined 출력
name_1 = "Alice"; // 할당 단계 : 변수에 값 할당

변수 호이스팅 (let, const)

let, const 키워드로 선언된 변수들도 var 키워드로 선언된 변수처럼 자바스크립트 엔진에 의해, 선언문이 해당 스코프의 최상단으로 끌어올려지기 때문에 호이스팅이 일어난다고 볼 수 있어요. 즉, 선언이 코드 실행 이전에, 메모리에 저장되는 과정은 맞다는 의미에요.

하지만, var 키워드로 선언된 변수와는 다르게, let, const 키워드로 선언된 변수들은 호이스팅이 발생하지 않는 것처럼 동작해요. 왜냐하면 초기화되지 않은 상태로 선언 자체만 메모리에 저장되기 때문이에요.

let, const로 선언된 변수의 경우, var로 선언된 변수와는 다르게 선언 단계와 초기화 단계가 분리되어 실행되요. 자바스크립트 엔진이 식별자를 기록하긴 하지만 값을 초기화하지 않기 때문에 선언문 이전에 식별자 값을 참조하려 하면 Reference Error가 발생하는 것이에요.

이렇게 let, const으로 선언되는 변수의 경우, 스코프의 최상단 지점으로 끌어올려진 선언부 지점이 아니라, 변수를 실질적으로 선언하는 라인을 실행하기 이전에는 식별자를 참조할 수 없다는 특징이 있어요. 이 참조 불가능한 구역을 일시적 사각지대(TDZ : Temporal Dead Zone)라고 해요.

console.log(name_1); // 출력 결과는 무엇일까?
let name_1 = "Alice";
↓ ↓ ↓ (자바스크립트 엔진 내부에서 처리되는 결과)
// 호이스팅 발생! 하지만 초기화되지 않음.
let name_1 =
console.log(name_1); // reference error 발생!
name_1 = "Alice"; // 할당 단계 : 변수에 값 할당
study_Javascript(); // 출력 결과는 무엇일까?
var study_Javascript = () => {
};
↓ ↓ ↓ (자바스크립트 엔진 내부에서 처리되는 결과)
var study_Javascript = undefined
study_Javascript(); // Type Error : 함수가 undefined로, 아직 함수로 인식되지 않음
var study_Javascript = () => {
};

함수 호이스팅 (함수 표현식)

함수를 표현하는 방법 중, 변수에 함수를 담아 함수를 선언하는 방식이 있어요. 이를 함수 표현식이라고 해요.

함수를 변수에 담고있기에, 변수 호이스팅과 똑같이 동작해요.

var 키워드로 선언한 경우에 선언문 이전에 함수를 실행하려 하면, undefined가 저장되어 있기 때문에, 이 데이터 타입은 호출될 수 없어요. 따라서 Type Error가 발생해요.

let, const 키워드로 선언한 경우에 선언문 이전에 함수를 실행하려 하면, 초기화 단계를 거치지 않았기 때문에, Reference Error가 발생해요.

해당 예제를 보면서 이해하고 넘어가도록 해요.

study_Javascript(); // 출력 결과는 무엇일까?
function study_Javascript(){
};
↓ ↓ ↓ (자바스크립트 엔진 내부에서 처리되는 결과)
// 선언과 동시에 함수가 생성되어 완성된 함수객체로서 호이스팅
function study_Javascript(){
};
study_Javascript(); // 문제없이 함수 실행

함수 호이스팅 (함수 선언문)

함수 표현식과 달리, function 키워드로 함수를 선언하는 함수 선언문은 동작방식과 그 결과가 조금 달라요.

함수 선언문 방식으로 함수를 선언하는 경우에는, 호이스팅이 자바스크립트 엔진이 함수 선언과 동시에, 완성된 함수객체를 생성해 환경 레코드에 기록하는 방식으로 이루어져요.* 환경 레코드는 실행 컨텍스트에서 자세히 다룰 예정이에요

즉, 함수의 선언 자체가 코드의 최상단으로 끌어올려진다는 뜻이에요. 이러한 함수 선언문 방식은 선언과 동시에 함수가 생성된다는 특징을 가지기 때문에 에러없이 실행되요.

마찬가지로 해당 예제를 보면서 이해하고 넘어가도록 해요.

그 외 추천 유튜브 영상

코딩 알려주는 누나

자바스크립트를 배우는데 아직도 let과 var의 차이를 모른다고? (호이스팅)

유튜브 보러가기

콘돌의터전

자바스크립트 const와 let의 호이스팅

유튜브 보러가기

얄팍한 코딩사전

[코딩만화] Scope가 뭔가요? (feat: let, const, var의 차이)

유튜브 보러가기