1. 호이스팅(Hoisting)이란?
호이스팅(Hoisting)은 자바스크립트에서 변수나 함수 선언이 코드 실행 전에 해당 스코프의 최상단으로 끌어올려지는 것처럼 동작하는 현상을 말합니다.
쉽게 말해, 코드를 위에서 아래로 읽는 것과는 다르게 자바스크립트 엔진이 먼저 변수와 함수의 선언부터 처리하는 것입니다.
물론 실제로 코드가 끌어올려져서 동작하는 것은 아닙니다. 자바스크립트 parser가 내부적으로 끌어올려서 처리를 하기 때문에 끌어올려지는 것처럼 동작하는 현상이라고 정의합니다.
Q. JS에만 있는 건가요? Java나 Python, C언어에는 호이스팅이 없나요? 😮
결론만 먼저 말하자면, 호이스팅이라는 이름의 동작이 없거나 구조적으로 차단되어 있습니다!
호이스팅은 자바스크립트처럼 인터프리터 언어이자 함수 스코프 기반의 동적 언어에서 드러나는 개념입니다.
조금 더 자세하게 설명해보자면. . .
JS는 인터프리터 언어로 실행 전에 코드를 두 번에 나눠 처리합니다.
인터프리터 언어
→ 소스코드를 한 줄 한 줄 읽어가며 명령을 바로 처리하는 프로그램(언어). 번역과 실행이 동시에 이루어짐
첫 번째 처리 → 선언 수집 (호이스팅)
두 번째 처리 → 실행
그러나 Java나 C는 컴파일 언어로, 실행 전에 모든 코드를 정적으로 분석하고 컴파일합니다.
컴파일 언어
→ 소스코드를 한꺼번에 다른 목적 코드로 번역한 후, 한 번에 실행하는 프로그램(언어)
선언이 순서에 따라 제한되어 있어, 선언 전에 접근하는 것은 컴파일 에러가 발생합니다.
따라서 이 경우는 호이스팅 같은 개념이 설계적으로 허용되지 않습니다.
Q. 그럼 Python은요? Python도 인터프리터 언어잖아요!
맞습니다. Python도 인터프리터 언어지만, 실행 순서에 따라 코드를 평가합니다.
그렇기에 JS처럼 선언을 끌어올리는 동작은 없습니다.
Python은 변수나 함수가 실제로 실행되는 시점에 존재해야 하며, 존재하지 않을 경우 NameError가 발생합니다.
호이스팅은 변수/함수 선언을 최상단으로 끌어올리는 것이 아닙니다.
끌어올려진 것 같은 현상을 말하는 것임을 명심하기!
2. JS의 변수 생성 단계
자바스크립트에서 변수는 총 3단계에 걸쳐 생성됩니다.
1단계 : 선언 단계 (Declaration phase)
스코프와 변수 객체가 생성되고, 스코프가 변수 객체를 참조합니다.
초기화 전까지는 TDZ 상태입니다.
2단계 : 초기화 단계 (Initalization)
변수 객체 값을 위한 공간을 메모리에 할당합니다.
이때 할당되는 값은 undefined입니다.
3단계 : 할당 단계 (Assignment)
변수 객체에 값을 할당합니다.
Q. TDZ가 대체 무엇인가요?
TDZ(Temporal Dead Zone)
스코프의 시작점부터 변수 선언이 실제로 실행되기 전까지의 구간을 의미합니다.
쉽게 설명하자면, 선언만 되고 아직 초기화 되지 않는 변수가 머무는 공간이라고 정의할 수 있겠네요.
이 구간에서는 해당 변수에 접근할 수 없고, 접근 시 ReferenceError가 발생하게 됩니다.
TDZ는 초기화 되지 않는 변수를 사용하는 것을 방지할 수 있기 때문에, 프로그래밍 오류를 줄이기 위해 필요합니다.
3. 호이스팅 : 변수와 함수, Class
자바스크립트에서 호이스팅이 발생하는 대상은 변수와 함수 선언입니다.
변수 선언 방식에 따라, 그리고 함수가 선언문인지 표현식인지에 따라 호이스팅의 방식이 달라집니다.
변수 : var vs let vs const
var
console.log(myVar); // undefined
var myVar = 'hello';
var는 선언과 동시에 undefined로 초기화됩니다.
그렇기에 우리가 작성한 코드는 위와 같지만, 실제로는 아래와 같이 진행됩니다.
var myVar; // 선언이 끌어올려짐 (초기화는 아직 안 됨)
console.log(myVar); // undefined
myVar = 'hello'; // 값 할당
즉 var의 경우에는, 선언이 호이스팅 되는 동시에 초기화(undefined)도 함께 일어납니다.
let, const
let과 const는 선언만 호이스팅 되고 초기화는 되지 않습니다.
console.log(myLet); // ReferenceError!
let myLet = 'hi';
선언된 시점까지 일시적 사각지대(TDZ)에 있기 때문에 접근하면 에러가 발생합니다.
즉, 위 코드에서 이름은 등록되어 있지만, 초기화되지 않아서 사용이 불가능합니다.
함수 선언 vs 함수 표현식
함수 선언문 : 전체가 호이스팅
sayHello(); // "Hello!"
function sayHello() {
console.log("Hello!");
}
함수 선언문의 경우에는 함수 전체가 미리 등록되므로, 코드 상단에서도 바로 호출이 가능합니다.
함수 표현식 : 변수만 호이스팅, 함수는 나중에
sayHi(); // TypeError: sayHi is not a function
var sayHi = function() {
console.log("Hi!");
};
sayHi 변수는 var처럼 undefined로 호이스팅 됩니다.
이는 아직 함수가 할당되지 않았기 때문에 호출 시 에러가 발생하게 됩니다.
Class 선언식 vs Class 표현식
Class 선언식 (declarations)
자바스크립트의 class 선언식은 호이스팅은 되지만, 초기화하지 않은 TDZ 상태로 유지됩니다.
따라서 class에 접근하기 위해서는 먼저 선언을 해야 합니다.
const user = new User(); // ReferenceError: Cannot access 'User' before initialization
class User {
constructor() {
this.name = '홍길동';
}
}
Class 표현식 (Expression)
표현식은 변수에 함수를 할당하듯 클래스도 할당하는 방식이기 때문에 호이스팅 되지 않습니다.
const user = new User(); // ReferenceError: Cannot access 'User' before initialization
const User = class {
constructor() {
this.name = '김철수';
}
};
마무리
호이스팅은 함수를 선언한 위치에 상관없이, 신경 쓰지 않고 필요한 곳에서 자유롭게 사용하기 위해 만들어진 기능입니다.
하지만 자유로운 만큼, 의도치 않은 버그가 생성될 수 있습니다.
호이스팅은 자바스크립트의 유연함이자 위험성 그 자체를 나타내는 기능입니다.
그렇기 때문에 호이스팅을 무조건 믿고 사용하기보다는 let, const, strict mode 등을 통해 호이스팅을 제한하는 방식도 고려하며 개발하는 것을 권장합니다.
출처
'Language > JavaScript' 카테고리의 다른 글
자바스크립트의 비동기와 콜백 (1) | 2025.04.27 |
---|---|
자바스크립트의 모듈 : 순환 참조 (0) | 2025.03.12 |
모듈 시스템 [CommonJS, AMD, UMD, ESM] (0) | 2025.03.10 |
나는 DOM이 무엇인지 알고 사용하고 있었을까? (0) | 2025.02.02 |