호이스팅
호이스팅 (Hoisting)
개요
호이스팅(Hoisting)은 자바스크립트 실행 컨텍스트(Execution Context) 가 생성될 때, 변수·함수 선언이 해당 컨텍스트의 최상단으로 끌어올려지는 동작을 의미한다. 이 과정은 코드가 실제로 실행되기 전에 이루어지며, 개발자가 변수와 함수를 선언한 위치와는 무관하게 선언 자체가 먼저 처리된다는 점에서 종종 혼동을 야기한다. 호이스팅을 올바르게 이해하면 런타임 오류를 예방하고, 코드 가독성과 유지보수성을 높일 수 있다.
핵심: 선언은 호이스팅되고, 초기화·할당은 실제 코드가 실행되는 순서대로 이루어진다.
실행 컨텍스트와 호이스팅
1. 실행 컨텍스트란?
- 전역 실행 컨텍스트: 스크립트가 로드될 때 최초 생성되는 컨텍스트. 전역 객체(
window혹은global)와 전역 스코프 체인을 포함한다. - 함수 실행 컨텍스트: 함수가 호출될 때마다 새로 생성되는 컨텍스트. 각각 독립적인 변수 환경(Variable Environment)과 스코프 체인을 가진다.
[eval](/doc/%EA%B8%B0%EC%88%A0/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D/JavaScript/eval)실행 컨텍스트:eval함수 내부에서 생성되는 특수 컨텍스트.
각 컨텍스트는 변수 환경 레코드(Variable Environment Record) 와 레퍼런스 환경 레코드(Reference Environment Record) 로 구성된다. 호이스팅은 변수 환경 레코드가 초기화되는 단계에서 발생한다.
2. 호이스팅 단계
| 단계 | 설명 |
|---|---|
| 1. 변수 환경 레코드 생성 | 선언식([var](/doc/%EA%B8%B0%EC%88%A0/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D/JavaScript/var), function, [let](/doc/%EA%B8%B0%EC%88%A0/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D/JavaScript/let), [const](/doc/%EA%B8%B0%EC%88%A0/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D/JavaScript/const))이 메모리 공간에 등록된다. var와 함수 선언은 [undefined](/doc/%EA%B8%B0%EC%88%A0/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D/JavaScript/undefined) 로 초기화된다. |
| 2. 스코프 체인 구성 | 현재 컨텍스트와 외부 컨텍스트를 연결해 변수 탐색 순서를 정의한다. |
| 3. 코드 실행 | 실제 코드가 위에서 아래로 실행되며, 변수에 값이 할당된다. |
변수 호이스팅
var 선언
console.log(num); // undefined
var num = 10;
var num)은 호이스팅되어 undefined 로 초기화된다.
- 할당(num = 10)은 코드가 실행되는 시점에 수행된다.
let·const 선언
console.log(age); // ReferenceError
let age = 20;
[ReferenceError](/doc/%EA%B8%B0%EC%88%A0/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D/JavaScript/ReferenceError) 가 발생한다.
- const는 선언과 동시에 초기화가 필요하다.
TDZ 예시
{
// TDZ 시작
console.log(a); // ReferenceError
let a = 5; // 초기화 시점, TDZ 종료
}
함수 호이스팅
함수 선언식 (Function Declaration)
greet(); // "Hello!"
function greet() {
console.log('Hello!');
}
함수 표현식 (Function Expression)
say(); // TypeError: say is not a function
var say = function() {
console.log('Hi');
};
say는 var에 의해 호이스팅되어 undefined 로 초기화된다.
- 실제 함수 객체는 할당 시점에 생성되므로, 호출 이전에 접근하면 [TypeError](/doc/%EA%B8%B0%EC%88%A0/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D/JavaScript/TypeError) 가 발생한다.
화살표 함수와 호이스팅
arrow(); // ReferenceError
let arrow = () => console.log('arrow');
let·const와 동일하게 TDZ에 속한다.
let·const와 호이스팅
| 특성 | var |
let |
const |
|---|---|---|---|
| 호이스팅 여부 | O (초기화 undefined) |
O (TDZ) | O (TDZ) |
| 재선언 허용 | O | X | X |
| 초기화 필요 | X | X | 필수 |
| 블록 스코프 | X | O | O |
- 블록 스코프:
{}로 둘러싼 영역 내부에서만 유효. - 재선언 금지: 같은 스코프 내에서 동일한 이름을 다시 선언하면
SyntaxError.
클래스와 호이스팅
new Person(); // ReferenceError
class Person {
constructor() { this.name = 'John'; }
}
let·const와 마찬가지로 TDZ에 놓인다.
- 선언 이전에 접근하면 ReferenceError 가 발생한다.
- 클래스 내부 메서드는 프로토타입에 자동으로 정의되며, 메서드 자체는 호이스팅되지 않는다.
호이스팅이 미치는 영향
- 코드 가독성
- 선언 위치와 실제 초기화 시점이 달라 가독성이 저하될 수 있다.
-
let·const사용으로 선언 위치와 초기화 시점을 명확히 할 수 있다. -
버그 발생 가능성
var와 함수 표현식에 의한undefined·TypeError가 흔히 발생한다.-
TDZ에 대한 이해 부족은
ReferenceError를 초래한다. -
성능
- 호이스팅 자체가 큰 성능 오버헤드를 일으키지는 않지만, 불필요한 전역 변수 생성은 메모리 사용량을 증가시킬 수 있다.
호이스팅 관련 오류와 디버깅
| 오류 | 발생 원인 | 해결 방안 |
|---|---|---|
ReferenceError: Cannot access 'x' before initialization |
let·const TDZ 위반 |
선언을 사용 전에 배치하거나, 선언을 최상단으로 이동 |
TypeError: x is not a function |
함수 표현식이 undefined 상태에서 호출 |
함수 선언식 사용 혹은 변수 할당 전에 호출 금지 |
ReferenceError: x is not defined |
전역/지역 변수 미선언 | 변수 선언을 명시적으로 추가 |
SyntaxError: Identifier 'x' has already been declared |
동일 스코프 내 중복 선언 (let·const) |
중복 선언 제거 또는 블록 스코프 조정 |
디버깅 팁
- 콘솔에 console.log 로 변수 선언 전후 값을 출력해 TDZ 여부 확인.
- ESLint 규칙 [no-use-before-define](/doc/%EA%B8%B0%EC%88%A0/%EA%B0%9C%EB%B0%9C%EB%8F%84%EA%B5%AC/IDE/no-use-before-define) 을 활성화해 사전 사용을 방지.
- 브라우저 DevTools 의 Scope 창을 활용해 현재 스코프와 변수 상태를 시각화.
모범 사례
let·const우선 사용- 블록 스코프와 TDZ를 활용해 선언 위치와 초기화를 명확히 함.
- 함수 선언식 대신 화살표 함수·함수 표현식 사용
- 선언 위치가 명확해 코드 흐름을 파악하기 쉬움.
- 전역 변수 최소화
- 전역 스코프에 변수를 선언하면 호이스팅이 복잡해지고 충돌 위험이 커짐.
- ESLint·Prettier 등 정적 분석 도구 활용
no-use-before-define,[prefer-const](/doc/%EA%B8%B0%EC%88%A0/%EA%B0%9C%EB%B0%9C%EB%8F%84%EA%B5%AC/IDE/prefer-const)같은 규칙으로 호이스팅 관련 버그를 사전에 차단.- 코드 리뷰 시 선언 위치 확인
- 특히
var와 함수 표현식이 섞여 있는 경우, 선언·할당 순서를 검증.
참고 자료
- ECMAScript 사양 – 13. Variable Statements, 14. Function Definitions, 15. Let and Const Declarations.
https://tc39.es/ecma262/ - MDN Web Docs – Hoisting
https://developer.mozilla.org/ko/docs/Glossary/Hoisting - “You Don’t Know JS” – Scope & Closures (Kyle Simpson) – 호이스팅과 스코프 체인 심층 분석.
- ESLint 규칙 문서 –
no-use-before-define,prefer-const.
https://eslint.org/docs/rules/no-use-before-define
본 문서는 자바스크립트 실행 컨텍스트와 호이스팅 메커니즘을 이해하고, 실무에서 발생할 수 있는 오류를 예방하기 위한 가이드라인을 제공한다.
이 문서는 AI 모델(gpt-oss-120b)에 의해 생성된 콘텐츠입니다.
주의사항: AI가 생성한 내용은 부정확하거나 편향된 정보를 포함할 수 있습니다. 중요한 결정을 내리기 전에 반드시 신뢰할 수 있는 출처를 통해 정보를 확인하시기 바랍니다.