본문 바로가기
JavaScript

[JavaScript] 호이스팅(Hoisting)

by 도전하는 린치핀 2024. 1. 24.

 

1. 호이스팅(Hoisting)

호이스팅(Hoisting)이란 함수내의 변수 및 함수의 선언들을 모두 유효 범위의 최상단으로 끌어올려 주는 JavaScript의 기능 중 하나이다.

 

실제 코드가 끌어올려 코드의 변화가 있는 것이 아니라 자바 스크립트 parser가 내부적으로 끌어올려 처리한다.

 

컴파일 단계에서 코드 실행 전 함수와 변수의 선언들을 스캔하여, 모든 함수와 변수 선언들은 렉시컬 환경이라 불리는 자바스크립트 데이터 구조 내의 메모리에 추가된다.

// 개발자가 작성한 코드 // 
console.log(a); // undefined
var a = "A"; // var 변수 

// 자바스크립트에서 호이스팅 된 코드 
var a; 
console.log(a);
a = "A";

 

  • a가 상단으로 호이스팅이 되었기 때문에 변수 선언 전 console.log를 출력하였을 때 에러가 발생하지 않고 undefined가 출력되는 것을 확인할 수 있다.
  • 이때 모든 선언(function, var, let, const, class)들은 JavaScript 내에서는 호이스팅이 되지만 var 선언은 undefined로 초기화 되지만 let과 const와 같은 선언은 초기화되지 않은 TDZ(Temporal Dead Zone) 상태로 유지되어 호이스팅 되지 않는 것처럼 보인다.

2. 변수의 호이스팅

 

JavaScript에서는 총 3단계로 변수를 생성한다.

  1. 선언 (Declaration) : 스코프와 변수 객체가 생성되고, 스코프가 변수 객체를 참조한다.(이때, 초기화하기 전에는 TDZ 상태로 있다.)
  2. 초기화 (Initialization) : 변수 객체 값을 위한 공간을 메모리로 할당한다.(이때, 할당되는 값은 undefined이다)
  3. 할당 (Assignment) : 변수 객체에 값을 할당한다.

 

2-1. var, let, const 호이스팅 비교

  • var : 선언과 동시에 초기화가 이루어져 undefined가 할당된다. (undefined로 호이스팅)
  • let, const : 선언만 이루어지고 초기화가 이루어지지 않아 메모리 할당되지 않은 TDZ에 들어가게 된다.(호이스팅이 되지 않는 것처럼 보이지만 실제로는 호이스팅이 이루어짐)
  • 결과적으로 모든 선언은 JavaScript에서 호이스팅되며, var 선언은 undefined로 초기화되지만 let, const 선언은 초기화되지 않은 상태로 유지된다.

 

undefined 와 ReferenceError 구분하기

// var의 경우 undefined로 호이스팅
console.log(hoist1); // Output: undefined
var hoist1 = 'Hello World';

//---------------------------------------------------
// let의 경우 ReferenceError 발생으로 호이스팅이 되지 않는 것처럼 보임
console.log(hoist2); // Output: ReferenceError: hoist is not defined ...
let hoist2 = 'Hello World';

 

 

let과 const 호이스팅이 되는 것 확인하기

var hoist = "var hoist";

function func() {
  console.log(hoist); // Output: ReferenceError
  let hoist = "let hoist";
};

 

만약 let과 const 변수가 호이스팅이 되지 않는다면 console.log를 진행했을 때 var 변수에 할당된 "var hoist"가 출력되어야 하지만 실제로는 함수 내에서 let hoist가 호이스팅 되어 ReferenceError가 발생하는 것을 볼 수 있다.

이를 통해 우리는 let과 const 또한 호이스팅이 진행된다는 것을 확인할 수 있다.

 

3. 함수의 호이스팅

 

함수는 3가지의 방법으로 작성할 수 있다.

  1. 함수 선언문 (Declaration) : 함수 선언 + 정의
  2. 함수 표현식 (Expression) : 표현식 = 식별자(변수명) + 연산자(=) + 리터럴(함수)
  3. 화살표 함수 : 단순히 표현만 간략해지는 것이 아니라 내부 동작 또한 간략화하는 방법

 

3-1. 함수 선언문의 호이스팅

함수 선언문의 경우 함수의 선언과 정의 모두 호이스팅되어 선언 전에 함수가 동작하여 사용 가능하다.

hoisting() // 함수 호이스팅 = function is hoisted

function hoisting() {
	console.log('function is hoisted')
}

 

3-2. 함수 표현식의 호이스팅

함수 호이스팅의 경우 함수를 변수로 선언하여 선언은 호이스팅이 되지만 정의가 되지 않아 undefined로 나타나 동작이 실행되지 않는다. 추가적으로 화살표 함수 또한 선언 전에 사용이 불가능하다.

hoisting // 변수 호이스팅 = ReferenceError: hoisting is not defined

const hoisting = function () {
	console.log('variable is hoisted')
}

 

 

  • 함수의 경우 모두 호이스팅되지만 선언문으로 작성한 함수의 경우 선언 + 정의가 호이스팅되어 코드 내에서 선언하기 전 함수를 사용할 수 있고 정상 작동한다.
  • 표현식이나 화살표 함수로 함수를 작성한 경우 변수로 판단하여 선언만 호이스팅되어 코드 내 선언하기 전 함수를 사용할 수 없고 Error가 발생한다.(호이스팅되지 않는 것처럼 보임)

 

아래는 변수와 함수에서 호이스팅이 동작하는 과정을 간단하게 그림으로 표현한 것이다.

 

결론적으로 호이스팅은 함수를 어디에 선언하던 신경쓰지 않고 필요한 곳에서 자유롭게 사용하기 위해 만들어진 기능이다. 하지만 이러한 기능은 개발자가 의도하지 않은 버그를 발생할 수 있으므로 개념은 알되 의도적으로 사용하지 않는 경우가 아니라면 사용하지 않는 것이 좋을 것 같다.

또한, TDZ로 초기화되는 let이나 const나 함수 표현식의 경우 사용하지 않는 것이 좋다.