본문 바로가기
언어 Language/자바스크립트 JavaScript

[JavaScript] 호이스팅(Hoisting)에 대해 알아보자

by 이땡칠 2022. 6. 9.

 

호이스팅(Hoisting)

 

 

먼저, 프로그래밍과 변수 개념을 정리합니다.

 

프로그래밍은 변수를 통해 값을 저장하고 참조하며 연산자로 값을 연산, 평가하고 조건문과 반복문에 의한 흐름제어로 데이터의 흐름을 제어하고 함수로 재사용이 가능한 구문의 집합을 만들며 객체, 배열 등으로 자료를 구조화하는 것이다.

 

변수는 값의 위치(주소)를 기억하는 저장소이다. 값의 위치란 값이 위치하고 있는 메모리 상의 주소(address)를 의미한다. 즉, 변수란 값이 위치하고 있는 메모리 주소(Memory address)에 접근하기 위해 사람이 이해할 수 있는 언어로 명명한 식별자(identifier)이다.

 

변수 선언과 할당의 구조 (출처)

 

변수는 var, let, const 키워드를 사용하여 선언하고 할당 연산자를 사용해 값을 할당한다. 그리고 식별자인 변수명을 사용해 변수에 저장된 값을 참조한다.

 

var score;  // 변수의 선언
score = 80; // 값의 할당
score = 90; // 값의 재할당
score;      // 변수의 참조

 

 

값을 할당하지 않은 변수 즉 선언만 되어 있는 변수는 undefined로 초기값을 갖는다. 선언하지 않은 변수에 접근하면 ReferenceError가 발생한다.

var x;
console.log(x); // undefined
console.log(y); // ReferenceError

 

이제 호이스팅을 알아봅니다.

아래의 예제를 보겠습니다.

console.log(foo); // ① undefined
var foo = 123;
console.log(foo); // ② 123
{
  var foo = 456;
}
console.log(foo); // ③ 456

 

var 키워드를 사용하여 선언한 변수는 중복 선언이 가능하기 때문에 위의 코드는 문법적으로 문제가 없습니다.

 

①에서 변수 foo는 아직 선언되지 않았으므로 ReferenceError: foo is not defined가 발생할 것을 기대했겠지만 콘솔에는 undefined가 출력됩니다.

 

이것은 다른 C-family 언어와는 차별되는 자바스크립트의 특징으로 모든 선언문은 호이스팅(Hoisting)되기 때문입니다.

호이스팅이란 var 선언문이나 function 선언문 등 모든 선언문이 해당 Scope의 선두로 옮겨진 것처럼 동작하는 특성을 말합니다. 즉, 자바스크립트는 모든 선언문(var, let, const, function, function*, class)이 선언되기 이전에 참조 가능합니다.

 

변수가 어떻게 생성되며 호이스팅은 어떻게 이루어지는지 좀더 자세히 살펴봅니다. 변수는 3단계에 걸쳐 생성됩니다.

선언 단계(Declaration phase)
변수 객체(Variable Object)에 변수를 등록한다. 이 변수 객체는 스코프가 참조하는 대상이 된다.

초기화 단계(Initialization phase)
변수 객체(Variable Object)에 등록된 변수를 메모리에 할당한다. 이 단계에서 변수는 undefined로 초기화된다.

할당 단계(Assignment phase)
undefined로 초기화된 변수에 실제값을 할당한다.

 

var 키워드로 선언된 변수는 선언 단계와 초기화 단계가 한번에 이루어집니다. 스코프에 변수가 등록되고 변수는 메모리에 공간을 확보한 후 undefined로 초기화됩니다. 따라서 변수 선언문 이전에 변수에 접근하여도 Variable Object에 변수가 존재하기 때문에 에러가 발생하지 않습니다. 다만 undefined를 반환한다. 이러한 현상을 변수 호이스팅(Variable Hoisting)이라고 합니다. 이후 변수 할당문에 도달하면 비로소 값의 할당이 이루어집니다.

 

앞에서 살펴본 예제를 호이스팅 관점에서 다시 한번 알아보면,

 

①이 실행되기 이전에 var foo = 123;이 호이스팅되어 ①구문 앞에 var foo;가 옮겨집니다. (실제로 변수 선언이 코드 레벨로 옮겨진 것은 아니고 변수 객체(Variable object)에 등록되고 undefined로 초기화된 것입니다.) 하지만 변수 선언 단계와 초기화 단계가 할당 단계와 분리되어 진행되기 때문에 이 단계에서는 foo에는 undefined가 할당되어 있습니다. 변수 foo에 값이 할당되는 것은 2행에서 실시됩니다.

 

②에서는 변수에 값이 할당되었기 때문에 123이 출력됩니다.

 

자바스크립트의 변수는 함수 레벨 스코프를 가지므로, 코드 블록 내의 변수 foo는 전역변수입니다. 전역에 선언된 변수 foo에 할당된 값을 재할당하기 때문에 ③의 결과는 456이 됩니다.

 

 

 

참고

https://poiemaweb.com/es6-block-scope

https://poiemaweb.com/js-data-type-variable#24-%EB%B3%80%EC%88%98-%ED%98%B8%EC%9D%B4%EC%8A%A4%ED%8C%85variable-hoisting

https://hanamon.kr/javascript-%ED%98%B8%EC%9D%B4%EC%8A%A4%ED%8C%85%EC%9D%B4%EB%9E%80-hoisting/

댓글