STUDY NOTE · 개념 정리
var vs let vs const 정리: 스코프, 호이스팅, TDZ
Frontend
var는 함수 스코프에 선언 전 접근하면undefined,let·const는 블록 스코프에 선언 전 접근하면 에러(TDZ)다.const는 재할당만 막을 뿐 객체 내용까지 얼리지는 않는다. 기본은const, 바꿔야 할 때만let,var는 쓰지 않는다.
1. 한눈에 비교
| 구분 | var | let | const |
| 스코프 | 함수 | 블록 { } | 블록 { } |
| 재선언 | 가능 | 불가 | 불가 |
| 재할당 | 가능 | 가능 | 불가 |
| 호이스팅 | 됨 (undefined로 초기화) | 됨 (초기화 안 됨, TDZ) | 됨 (초기화 안 됨, TDZ) |
| 선언 전 접근 | undefined | ReferenceError | ReferenceError |
| 전역에서 선언 시 | 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. 정리
- 기본은
const. 읽는 사람이 '이 값은 다시 안 바뀐다'는 걸 바로 안다. - 다시 할당해야 하면
let(반복 카운터, 누적값). var는 함수 스코프·재선언·전역 오염 때문에 쓰지 않는다.- 호이스팅은 셋 다 되지만,
let·const는 TDZ 때문에 선언 전에 쓸 수 없다.