← 개인 공부 · Frontend
STUDY NOTE · 개념 정리

var vs let vs const 정리: 스코프, 호이스팅, TDZ

Frontend
var는 함수 스코프에 선언 전 접근하면 undefined, let·const는 블록 스코프에 선언 전 접근하면 에러(TDZ)다. const는 재할당만 막을 뿐 객체 내용까지 얼리지는 않는다. 기본은 const, 바꿔야 할 때만 let, var는 쓰지 않는다.

1. 한눈에 비교

구분varletconst
스코프함수블록 { }블록 { }
재선언가능불가불가
재할당가능가능불가
호이스팅됨 (undefined로 초기화)됨 (초기화 안 됨, TDZ)됨 (초기화 안 됨, TDZ)
선언 전 접근undefinedReferenceErrorReferenceError
전역에서 선언 시window 속성이 됨window 속성 아님window 속성 아님
선언만 하기가능가능불가 (값 필수)

2. 스코프: 함수 vs 블록

function test() {
if (true) {
var a = 1;
let b = 2;
}
console.log(a); // 1 (var는 함수 전체가 범위)
console.log(b); // ReferenceError (let은 if 블록 안에서만)
}

3. 호이스팅과 TDZ

호이스팅은 '선언이 스코프 맨 위로 끌어올려진 것처럼 동작하는 것'이다. 실제로 코드가 옮겨지는 건 아니고, 실행 전에 스코프의 선언을 먼저 등록하기 때문에 생기는 현상이다.

console.log(x); // undefined — var는 등록과 동시에 undefined로 초기화
var x = 10;

console.log(y); // ReferenceError — 등록은 됐지만 초기화 전
let y = 20;

let·const도 호이스팅은 된다. 다만 선언문을 실행하기 전까지는 초기화되지 않은 상태로 남는데, 이 구간을 TDZ(Temporal Dead Zone, 일시적 사각지대)라고 한다. 호이스팅이 안 된다면 아래 코드는 바깥 v를 찍어야 하지만 실제로는 에러가 난다.

let v = "outer";
{
console.log(v); // ReferenceError — 안쪽 v가 이미 등록돼 있어서 바깥 v를 가림
let v = "inner";
}
키워드등록초기화할당
var스코프 진입 시등록과 동시에 undefined할당문 실행 시
let스코프 진입 시선언문 실행 시할당문 실행 시
const스코프 진입 시선언문 실행 시 (값과 함께)재할당 불가
function 선언문스코프 진입 시함수 전체가 바로 준비됨-

4. 반복문과 클로저: 면접 단골 문제

for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i)); // 3, 3, 3
}
for (let j = 0; j < 3; j++) {
setTimeout(() => console.log(j)); // 0, 1, 2
}

var i는 함수 전체에 하나뿐이라 콜백 세 개가 같은 i를 보고, 실행될 때는 이미 3이다. let은 반복마다 새 바인딩을 만들어서 각 콜백이 그 회차의 값을 기억한다.

5. const는 '상수'가 아니다

const user = { name: "kim" };
user.name = "lee"; // 가능: 객체 내용 변경
user = { name: "park" }; // TypeError: 재할당 불가

const frozen = Object.freeze({ name: "kim" });
frozen.name = "lee"; // 무시됨 (strict 모드에선 에러)

const가 막는 건 '변수가 다른 값을 가리키는 것'이다. 내용까지 막으려면 Object.freeze를 쓰는데, 이것도 한 단계(얕게)만 얼린다.

6. 정리

  1. 기본은 const. 읽는 사람이 '이 값은 다시 안 바뀐다'는 걸 바로 안다.
  2. 다시 할당해야 하면 let (반복 카운터, 누적값).
  3. var는 함수 스코프·재선언·전역 오염 때문에 쓰지 않는다.
  4. 호이스팅은 셋 다 되지만, let·const는 TDZ 때문에 선언 전에 쓸 수 없다.
Gunmo Lee
var vs let vs const 정리: 스코프, 호이스팅, TDZ | Gunmo's Dev Life