본문 바로가기
JavaScript

[JavaScript] 호이스팅(Hoisting)이란?

by kind1230 2024. 2. 12.

호이스팅(hoisting)

호이스팅은 자바스크립트에서 특별한 동작 원리를 지칭한다. 많이 오해하는 바와 달리, 호이스팅은 변수나 함수의 선언을 물리적으로 코드의 최상단으로 이동시키는 것이 아니라, 선언을 스코프의 최상단에 위치한 것처럼 자바스크립트 엔진이 해석하는 현상을 말한다.

  1. 호이스팅 정의: 자바스크립트에서 선언(변수, 함수 등)을 코드 상단에 위치한 것처럼 엔진이 처리하는 현상.
  2. 물리적 이동 없음: 실제로 코드의 위치가 변경되는 것이 아니라, 자바스크립트 엔진이 선언을 코드 실행 전에 먼저 인식함.
  3. 실행 컨텍스트 생성: 코드 실행 전, 스코프 내의 모든 선언을 스코프 최상위에 있는 것처럼 처리하는 과정의 일부.
  4. var와 함수 선언의 호이스팅: var로 선언된 변수와 함수 선언문은 선언 전 참조/호출해도 오류가 발생하지 않음.
  5. let과 const의 특별한 경우: let, const로 선언된 변수는 호이스팅 되지만, 일시적 사각지대(Temporal Dead Zone, TDZ)에 의해 선언 전 참조 시 오류 발생.
  6. 실용적 이해: 호이스팅 이해는 코드의 동작 방식을 명확히 파악하고, 오류를 방지하는 데 도움을 줌.

 

var, let, const 의 차이점

  • var: 선언과 동시에 undefined로 초기화된다. 이 때문에 선언 전 참조해도 undefined가 반환되며, 에러가 발생하지 않는다.
  • let, const: 선언은 되지만, 초기화는 선언문에 도달했을 때 이루어진다. 초기화 전에 참조하려 하면 참조 에러(ReferenceError)가 발생하고, 이 구간을 '일시적 사각지대(Temporal Dead Zone, TDZ)'라고 한다.

 

호이스팅 과정

  1. 선언 단계: 실행 컨텍스트의 변수 객체에 변수를 등록한다. 이 변수 객체가 스코프의 참조 대상이 된다.
  2. 초기화 단계: 메모리에 변수를 위한 공간을 확보하고, 변수를 undefined로 초기화한다. (단, let과 const는 이 단계에서 초기화되지 않는다.)
  3. 할당 단계: 실제 값을 변수에 할당.

모든 변수 선언은 호이스팅된다. 단, var는 선언과 초기화가 동시에 이루어지고, let과 const는 선언 후 별도로 초기화되며, 초기화 전 접근 시 에러가 발생한다.

let과 const도 호이스팅이 일어나지만, TDZ 때문에 선언 전에 접근하면 에러가 발생한다. var로 선언된 변수는 호이스팅으로 인해 선언 전 참조해도 에러 없이 undefined가 반환되지만, let과 const는 TDZ에 의해 에러가 발생한다.

 

예시코드

❗️ 유효 범위와 스코프 - 사전지식

1. 함수 스코프: var로 선언된 변수는 함수 블록 내에서만 유효하다.
2. 블록 스코프: let, const로 선언된 변수는 중괄호 {}로 감싸진 블록 내에서만 유효하다.
function exampleFunction() {
  var functionScoped = "저는 함수 안에서만 존재해요!";
  if (true) {
    var stillFunctionScoped = "저도 함수 안이면 어디든지 있을 수 있어요!";
    let blockScoped = "저는 이 블록 안에서만 존재해요!";
    const anotherBlockScoped = "저도 이 블록 안에서만요!";
  }
  console.log(functionScoped); // 출력됨
  console.log(stillFunctionScoped); // 출력됨
  console.log(blockScoped); // 에러: blockScoped는 정의되지 않았습니다.
  console.log(anotherBlockScoped); // 에러: anotherBlockScoped는 정의되지 않았습니다.
}

exampleFunction();​

 

예제1) 'var' 를 사용한 호이스팅 예시

console.log(myVar); // undefined 출력
var myVar = 'Hello World!'; 
console.log(myVar); // 'Hello World!' 출력

 

  • var로 선언된 변수는 호이스팅으로 인해 선언이 코드 상단으로 끌어올려진다. (끌어올려지는 현상.)
  • 초기화(undefined로 설정)도 선언과 함께 이루어지므로, 첫 번째 console.log에서 에러가 발생하지 않고 undefined가 출력된다.

 

예제2) 'let'을 사용한 호이스팅 예시

let test = 1; // 전역 변수 foo 선언 및 할당
{
  console.log(test); // TDZ 에러 발생
  let test = 2;  // 블록 스코프 내 새로운 foo 선언 및 할당
}

 

  • 전역 변수 foo: 전역 스코프에서 foo는 1로 초기화됩니다.
  • 블록 스코프: 중괄호 {} 안에서 foo를 2로 재선언.
  • TDZ: 'console.log(foo);' 가 블록 스코프 내의 새 foo 선언 전에 실행되기 때문에, 이 시점에서 새 foo는 TDZ에 있다. TDZ 내에서 변수에 접근하려 하면 참조 에러가 발생

 

예제3) ' const '를 사용한 선언에서의 오류 예시

const myConst; // SyntaxError: Missing initializer in const declaration
myConst = 'Hello World!';
console.log(myConst); // 이 코드는 실행되지 않음

 

'const'로 선언된 변수는 반드시 선언과 동시에 초기화되어야 한다. 초기화 없이 선언만 하려고 하면 구문 에러(SyntaxError)가 발생한다.

 

예제4) 함수 선언에서의 호이스팅 예시

func1(); // 'Hello' 출력
func2(); // TypeError: func2 is not a function
function func1() {
  console.log('Hello');
}
var func2 = function() {
  console.log('world');
}

 

함수 선언문과 호이스팅

함수 선언문(function func1() { ... })은 호이스팅되어, 코드의 어느 곳에서든지 호출할 수 있다. 이는 JavaScript 엔진이 실행 전에 함수 선언을 메모리에 저장하기 때문, 따라서 func1(); 호출은 정상적으로 작동하여 'Hello'를 출력한다.

함수 표현식과 호이스팅

함수 표현식(var func2 = function() { ... };)의 경우, 변수 func2는 호이스팅되지만, 변수의 할당은 실행 흐름이 해당 라인에 도달했을 때 이루어진다. 즉, func2 변수는 호이스팅으로 인해 선언은 되어 undefined로 초기화되지만, func2에 함수가 할당되기 전에 func2 ();를 호출하려 하면 func2 는 아직 함수가 아닌 undefined 상태이다. 이로 인해 TypeError: func2 is not a function 오류가 발생한다.

'JavaScript' 카테고리의 다른 글

[JavaScript] BFcache란 ?  (0) 2024.09.09
[JavaScript] 메모이제이션 (Memoization)  (0) 2024.01.01