| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 |
- Git
- react
- 개발자
- html
- 프론트앤드
- 코딩테스트
- 백준
- 코딩
- 알고리즘
- 프론트엔드
- javascript
- DFS
- 크래프톤 정글
- HTML기초
- 해시
- Mini-React
- frontend
- CSS
- 프로그래머스
- Python
- c언어
- 정글
- js
- 팀프로젝트
- 알고리즘 기초
- 그리디
- 혼자 공부해서 개발까지
- BFS
- 정렬
- 그래프
- Today
- Total
민혁이의 IT스토리
var를 쓰면 안 되는 이유: 호이스팅과 TDZ로 알아보는 스코프의 차이 본문
요즘은 클론 코딩이나 AI의 도움으로 무엇이든 뚝딱 만들어낼 수 있는 시대입니다. 그래서인지 이제 더 이상
언어의 깊은 곳까지 공부할 필요가 있을까?'라는 회의적인 시선도 종종 보입니다.
하지만 저는 오히려 그렇기 때문에 개발자가 자신의 주력 언어를 더 깊이 있게 파고들어야 한다고 생각합니다. '어떻게' 구현하는지를 넘어 '왜' 그렇게 동작하는지를 아는 힘이 결국엔 차이를 만드니까요. 그 다짐으로 다시 자바스크립트의 가장 기초이자 핵심인 실행 컨텍스트를 들여다보게 되었습니다.
모던 자바스크립트(ES6+)를 배우면 가장 먼저 듣는 조언이 있습니다. "var는 이제 잊으세요. 무조건 let과 const만 쓰세요."
하지만 면접관이 "왜 var를 쓰면 안 되나요?"라고 묻거나, 혹은 레거시 코드를 유지보수하다가 var로 인한 기이한 버그를 마주했을 때,
단순히 "쓰지 말라니까요"라고 답할 수는 없습니다.
오늘은 자바스크립트 엔진이 코드를 실행하는 과정인 실행 컨텍스트를 통해, var가 왜 위험한지, 그리고 let/const가 어떻게 우리를 안전하게 지켜주는지(TDZ) 알아보겠습니다.
코드가 실행되기도 전에 변수를 안다? (실행 컨텍스트)
자바스크립트 엔진은 코드를 한 줄씩 읽기 전에 '실행 컨텍스트(Execution Context)'라는 환경을 먼저 구성합니다. 이 과정은 크게 두 단계로 나뉩니다.
- 생성 단계 (Creation Phase): 코드를 전체적으로 훑으며 변수와 함수 선언을 찾아 메모리에 미리 등록합니다. (호이스팅 발생)
- 실행 단계 (Execution Phase): 실제로 코드를 한 줄씩 실행하며 값을 할당합니다.
우리가 흔히 말하는 호이스팅(Hoisting)은 1번 생성 단계에서 변수명(식별자)들이 스코프의 최상단으로 끌어올려진 것처럼 메모리에 등록되기 때문에 발생하는 현상입니다.
문제는 이 '호이스팅'을 처리하는 방식이 var와 let/const가 다르다는 점입니다.
var의 문제점: 너무 친절한 호이스팅
var는 생성 단계에서 변수를 등록할 때, undefined로 값까지 초기화해버립니다. 그래서 선언하기도 전에 변수를 호출해도 에러가 나지
않습니다.
console.log(myVar); // undefined (에러가 안 남!)
var myVar = "Hello";
console.log(myVar); // "Hello"
- 상식: "선언 안 한 변수니까 에러가 나야지!"
- var의 현실: "아, myVar? 메모리에 있는데 아직 값은 없어. undefined 줄게."
이런 느슨한 동작은 코드가 길어졌을 때, 변수가 어디서 선언되었는지 추적하기 어렵게 만들고 의도치 않은 로직 실행을 허용하여 치명적인 버그를 만듭니다.
let/const의 해결책: TDZ (일시적 사각지대)
ES6에서 등장한 let과 const도 호이스팅이 될까요? 네, 됩니다. 하지만 var처럼 친절하게 undefined로 초기화해주지 않습니다. 대신 TDZ(Temporal Dead Zone)라는 감옥에 가둬둡니다.
console.log(myLet); // ReferenceError: Cannot access 'myLet' before initialization
let myLet = "Hello";
- 생성 단계: myLet이라는 이름을 메모리에 등록합니다. (호이스팅 O)
- TDZ: 하지만 선언문(let myLet)을 만날 때까지는 이 변수에 접근을 막습니다. (초기화 X)
- 실행 단계: 선언문을 만나면 그제야 TDZ에서 풀려나고 값이 할당됩니다.
TDZ 덕분에 우리는 "변수는 선언한 뒤에 써야 한다"는 당연한 상식을 코드 레벨에서 강제받을 수 있게 되었습니다.
스코프의 차이: 함수 vs 블록
var를 쓰지 말아야 할 또 다른 결정적인 이유는 스코프(유효 범위)의 차이입니다.
- var: 함수 레벨 스코프 (Function Scope)
var는 오직 함수(Function)만 스코프로 인정합니다. if문이나 for문 같은 블록({})은 무시하고 전역 변수처럼 튀어나갑니다.
if (true) {
var x = 10;
}
console.log(x); // 10 (if문 밖에서도 접근 가능... 충격)
- let/const: 블록 레벨 스코프 (Block Scope)
let과 const는 모든 코드 블록({})을 스코프로 인정합니다. 훨씬 직관적이고 안전합니다.
if (true) {
let y = 20;
}
console.log(y); // ReferenceError: y is not defined (안전함)
결론
자바스크립트 엔진은 언제나 실행 컨텍스트를 생성하며 변수를 미리 등록(호이스팅)합니다.
- var는 이 과정에서 섣불리 undefined로 초기화되고, 스코프 규칙도 헐거워서 예측 불가능한 코드를 만듭니다.
- 반면 let과 const는 TDZ를 통해 변수가 선언되기 전 접근을 차단하고, 엄격한 블록 스코프를 따릅니다.
그러니 이제 레거시 코드를 볼 때 var가 보이면 "아, 호이스팅과 함수 스코프 때문에 사이드 이펙트가 발생할 수 있겠구나"라고 이해하고, 여러분이 작성하는 새 코드에는 반드시 let과 const를 사용하세요!
'혼자 공부해서 개발까지 > JavaScript' 카테고리의 다른 글
| [Mini React 만들기 #3] - 리랜더링 구현하기 (0) | 2026.03.20 |
|---|---|
| [Mini React 만들기 #2] - 브라우저가 멈추는 문제를 해결하자: Concurrent Mode와 Fiber 도입기 (0) | 2026.03.13 |
| [Mini React 만들기 #1] - Virtual DOM구현과 렌더링 (2) | 2026.03.10 |
| [JS 기초] 카멜레온 같은 정체성, this 이해하기 (0) | 2026.02.12 |
| 실행 컨텍스트가 사라져도 데이터가 남는 이유 (Call Stack vs Closure) (0) | 2026.02.11 |