JavaScript: var, let, const
자바스크립트에서 변수를 선언하는 방법은 세 가지가 있다: var, let, 그리고 const.
그런데 이 셋은 단순히 문법이 다른 게 아니다.
동작 방식 자체가 다르다.
그래서 어떤 걸 쓰느냐에 따라 버그가 생길 수도, 막을 수도 있다.
이번 글에서는 var, let, const를 스코프(Scope), 중복 선언, 호이스팅(Hoisting), 전역 객체(window) 네 가지 관점에서 비교해본다.
1. 스코프: 변수가 살아 있는 공간
var: 함수 스코프
var는 오직 함수 단위로만 스코프를 나눈다. {} 블록은 무시한다.
if (true) {
var x = 1;
}
console.log(x); // 1 (밖에서도 접근됨)
함수 안에서 선언하면 그 함수 안에서만 유효하지만, 함수 바깥에서 {} 안에 선언하면 밖에서도 살아 있다.
let, const: 블록 스코프
let과 const는 {} 블록 안에서만 살아 있다. 가장 큰 차이점이자 장점이다.
if (true) {
let y = 2;
const z = 3;
}
console.log(y); // ReferenceError
console.log(z); // ReferenceError
블록 단위로 스코프가 나뉘기 때문에 변수의 생명 주기를 더 명확하고 안전하게 관리할 수 있다.
for문에서 차이
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
} // 3, 3, 3
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
} // 0, 1, 2
왜 이런 차이가 발생할까?
- var는 함수 스코프이기 때문에 for 루프가 돌더라도 같은 i를 계속 공유한다.
루프가 끝난 시점에서의 i = 3을 참조하게 된다. - let은 블록 스코프라서 루프가 돌 때마다 각각의 i가 새로운 스코프에서 생성된다.
그래서 setTimeout 콜백 안에서도 올바른 값이 유지된다.
2. 중복 선언: 같은 이름, 두 번 선언할 수 있을까?
var: 가능함 (하지만 위험함)
var a = 1;
var a = 2; // 가능
덮어쓰기도 되고, 오류도 안 난다. 이게 생각보다 위험하다.
의도치 않게 같은 이름으로 재선언해도 아무런 경고 없이 통과된다.
let, const: 불가능
let b = 1;
let b = 2; // ❌ SyntaxError
const c = 3;
const c = 4; // ❌ SyntaxError
동일한 스코프 안에서는 중복 선언 자체가 불가능하다.
이게 코드를 예측 가능하게 만든다.
3. 호이스팅: 선언이 끌어올려진다?
자바스크립트는 실행 전에 변수 선언과 함수 선언을 먼저 메모리에 올려둔다.
이를 호이스팅이라고 한다.
var: 선언만 끌어올려지고, 값은 undefined
console.log(d); // undefined
var d = 5;
실제로는 이렇게 처리된다:
var d;
console.log(d); // undefined
d = 5;
let, const: TDZ(일시적 사각지대)에 갇힘
console.log(e); // ❌ ReferenceError
let e = 10;
let, const도 호이스팅은 되지만, 초기화 전에 접근하면 에러가 난다. [ 그래서 더욱 안전하다 ]
이 현상을 **TDZ(Temporal Dead Zone)**이라고 부른다.
4. 전역 객체(window)에 등록되는가?
브라우저 환경에선 최상위 스코프에 선언된 변수들이 window 객체의 프로퍼티로 올라간다. 그런데 이것도 셋 다 다르다.
var: 등록된다
var f = 100;
console.log(window.f); // 100
var로 전역 선언하면 window 객체에 자동으로 붙는다.
그래서 실수로 전역 내장 객체(alert, location 등)를 덮어쓸 위험도 있다.
let, const: 등록되지 않는다
let g = 200;
const h = 300;
console.log(window.g); // undefined
console.log(window.h); // undefined
let, const는 전역에서 선언돼도 window에 등록되지 않는다. [ 그래서 전역 오염이 훨씬 적다. ]
🔚 정리: 언제 무엇을 써야 할까?
구분 | var | let | const |
스코프 | 함수 | 블록 | 블록 |
중복 선언 | 가능 | 불가능 | 불가능 |
호이스팅 | 선언만(undefined) | TDZ 존재 | TDZ 존재 |
window 등록 | 됨 | ❌ 안 됨 | ❌ 안 됨 |
재할당 가능 | 가능 | 가능 | ❌ 불가능 |
✍️ 실무 기준 추천
- var는 이제 쓰지 말자. 예측 불가능하고 안전하지 않다.
- 기본은 const: 재할당이 불필요하다면 const로 선언해두는 게 실수를 줄인다.
- 변화가 필요한 값에만 let을 쓰자.
const user = { name: 'lee' }; // ✅ 객체 내부는 바뀔 수 있음
user.name = 'kim';
let count = 0;
count += 1;
참고