본문으로 건너뛰기 JavaScript var vs let vs const 완벽 비교 | 변수 선언 방식 선택 가이드

JavaScript var vs let vs const 완벽 비교 | 변수 선언 방식 선택 가이드

JavaScript var vs let vs const 완벽 비교 | 변수 선언 방식 선택 가이드

이 글의 핵심

JavaScript var, let, const의 차이점을 스코프, 호이스팅, 재할당 관점에서 비교. 실전에서 어떤 것을 써야 하는지 선택 기준과 예제를 설명합니다.

들어가며

“var를 써도 되나요?” JavaScript를 배울 때 자주 나오는 질문입니다. 이 글에서는 var, let, const의 차이를 명확히 이해하며, 실전에서 어떤 것을 써야 하는지 선택 기준을 제시합니다. 비유로 말씀드리면, var건물 전체가 하나의 방처럼 들리는 스피커, let회의실 칸막이, const한 번 붙인 이름표를 못 바꾸는 자리에 가깝습니다. 루프·블록 단위로 변수를 나누려면 letconst가 맞습니다.

언제 let을, 언제 const를 쓰나요? (var는?)

관점constletvar
성능동일 계열에서 차이는 미미동일호이스팅·스코프로 버그 유발이 잦음
사용성재할당이 없을 때 기본재할당이 필요할 때레거시·특수 호환 외에는 비권장
적용 시나리오대부분의 바인딩카운터·스왑 등구형 코드 유지

이 글을 읽으면

  • var, let, const의 스코프 차이를 이해합니다
  • 호이스팅이 각각 어떻게 동작하는지 배웁니다
  • 재할당과 재선언의 차이를 익힙니다
  • 실전에서 어떤 것을 써야 하는지 판단할 수 있습니다

1. 빠른 비교표

특성varletconst
스코프함수 스코프블록 스코프블록 스코프
호이스팅선언 + 초기화 (undefined)선언만 (TDZ)선언만 (TDZ)
재할당✅ 가능✅ 가능❌ 불가능
재선언✅ 가능❌ 불가능❌ 불가능
전역 객체window에 추가추가 안 됨추가 안 됨
권장 사용❌ 사용 금지✅ 재할당 필요 시✅ 기본 선택

2. 스코프 차이

var: 함수 스코프

function testVar() {
    if (true) {
        var x = 10;
    }
    console.log(x); // ✅ 10 (블록 밖에서도 접근 가능)
}
testVar();

let/const: 블록 스코프

function testLet() {
    if (true) {
        let x = 10;
        const y = 20;
    }
    console.log(x); // ❌ ReferenceError: x is not defined
    console.log(y); // ❌ ReferenceError: y is not defined
}

실전 문제: 루프 변수

// var의 함정
for (var i = 0; i < 3; i++) {
    setTimeout(() => {
        console.log(i); // 3, 3, 3 (예상: 0, 1, 2)
    }, 100);
}
// let으로 해결
for (let i = 0; i < 3; i++) {
    setTimeout(() => {
        console.log(i); // 0, 1, 2 ✅
    }, 100);
}

이유: var는 함수 스코프이므로 루프가 끝난 후 i = 3이 됩니다. let은 각 반복마다 새로운 블록 스코프를 생성합니다.

3. 호이스팅

var: 선언 + 초기화 호이스팅

console.log(x); // undefined (에러 아님!)
var x = 10;
// 실제 동작
var x = undefined; // 호이스팅
console.log(x);    // undefined
x = 10;

let/const: TDZ (Temporal Dead Zone)

console.log(x); // ❌ ReferenceError: Cannot access 'x' before initialization
let x = 10;
// TDZ: 스코프 시작부터 선언까지의 구간
{
    // TDZ 시작
    console.log(x); // ❌ ReferenceError
    let x = 10;     // TDZ 끝
    console.log(x); // ✅ 10
}

실전 예제

// var의 문제
function getUser() {
    if (!user) {
        var user = fetchUser(); // 호이스팅으로 전체 함수 스코프
    }
    return user; // undefined 반환 가능
}
// let으로 해결
function getUser() {
    if (!user) {
        let user = fetchUser(); // 블록 스코프
    }
    return user; // ❌ ReferenceError (의도한 대로 에러)
}

4. 재할당과 재선언

var: 재할당, 재선언 모두 가능

var x = 10;
var x = 20; // ✅ 재선언 가능 (위험!)
x = 30;     // ✅ 재할당 가능

let: 재할당 가능, 재선언 불가

let x = 10;
let x = 20; // ❌ SyntaxError: Identifier 'x' has already been declared
x = 30;     // ✅ 재할당 가능

const: 재할당, 재선언 모두 불가

const x = 10;
const x = 20; // ❌ SyntaxError
x = 30;       // ❌ TypeError: Assignment to constant variable

5. const의 불변성

주의: const는 참조만 불변

// 기본 타입: 완전 불변
const x = 10;
x = 20; // ❌ TypeError
// 객체: 참조는 불변, 내용은 가변
const obj = { name: 'Alice' };
obj = { name: 'Bob' }; // ❌ TypeError (참조 변경 불가)
obj.name = 'Bob';      // ✅ 가능 (내용 변경 가능)
// 배열: 참조는 불변, 요소는 가변
const arr = [1, 2, 3];
arr = [4, 5, 6];  // ❌ TypeError
arr.push(4);      // ✅ 가능
arr[0] = 10;      // ✅ 가능

완전 불변 객체

// Object.freeze로 완전 불변
const obj = Object.freeze({ name: 'Alice' });
obj.name = 'Bob'; // ❌ 무시됨 (strict mode에서는 TypeError)
// 깊은 불변성 (중첩 객체)
function deepFreeze(obj) {
    Object.freeze(obj);
    Object.values(obj).forEach(value => {
        if (typeof value === 'object' && value !== null) {
            deepFreeze(value);
        }
    });
    return obj;
}
const config = deepFreeze({
    api: {
        url: 'https://api.example.com',
        timeout: 5000,
    },
});
config.api.url = 'https://evil.com'; // ❌ 무시됨

6. 실전 선택 가이드

기본 원칙

// 1순위: const (기본)
const API_URL = 'https://api.example.com';
const users = [];
// 2순위: let (재할당 필요 시)
let count = 0;
for (let i = 0; i < 10; i++) {
    count += i;
}
// 3순위: var (사용 금지!)
// 레거시 코드에서만 볼 수 있음

상황별 선택

상황선택이유
상수const재할당 방지
루프 변수let블록 스코프
카운터let재할당 필요
객체/배열const참조 불변 (내용은 가변)
함수const재할당 방지
레거시var기존 코드 유지보수만

ESLint 설정

// .eslintrc.json
{
  "rules": {
    "no-var": "error",           // var 금지
    "prefer-const": "warn",      // 재할당 없으면 const 권장
    "no-const-assign": "error"   // const 재할당 금지
  }
}

7. 흔한 실수

실수 1: var 재선언

var user = 'Alice';
// ... 100줄 후 ...
var user = 'Bob'; // ✅ 에러 없음 (의도치 않은 재선언!)
// let으로 방지
let user = 'Alice';
let user = 'Bob'; // ❌ SyntaxError

실수 2: 루프 클로저

// var의 함정
var funcs = [];
for (var i = 0; i < 3; i++) {
    funcs.push(function() {
        return i;
    });
}
console.log(funcs[0]()); // 3 (예상: 0)
console.log(funcs[1]()); // 3 (예상: 1)
console.log(funcs[2]()); // 3 (예상: 2)
// let으로 해결
for (let i = 0; i < 3; i++) {
    funcs.push(function() {
        return i;
    });
}
console.log(funcs[0]()); // 0 ✅
console.log(funcs[1]()); // 1 ✅
console.log(funcs[2]()); // 2 ✅

실수 3: const 객체 수정 시도

const config = { debug: true };
// ❌ 잘못된 이해
config = { debug: false }; // TypeError
// ✅ 올바른 이해
config.debug = false; // 가능

8. 전역 객체와의 관계

var는 전역 객체에 추가

var globalVar = 'I am global';
console.log(window.globalVar); // 'I am global' (브라우저)
let globalLet = 'I am global';
console.log(window.globalLet); // undefined
const globalConst = 'I am global';
console.log(window.globalConst); // undefined

왜 문제인가?

// 기존 전역 변수 덮어쓰기
var alert = 'oops';
alert('Hello'); // ❌ TypeError: alert is not a function

마무리

JavaScript 변수 선언의 핵심:

  1. const를 기본으로 사용하세요
  2. 재할당이 필요하면 let 사용
  3. var는 절대 사용하지 마세요
  4. ESLint로 자동 검사 설정 핵심: const > let > var 순서로 고려하며, var는 레거시 코드에서만 보게 될 것입니다.

FAQ

Q1. const를 쓰면 성능이 더 좋나요? 미미한 차이입니다. const의 주요 이점은 의도 표현실수 방지입니다. Q2. 모든 변수를 const로 선언해야 하나요? 재할당이 필요 없다면 const를 사용하세요. 코드 리뷰어가 “이 변수는 바뀌지 않는구나”를 바로 알 수 있습니다. Q3. 기존 코드의 var를 모두 let/const로 바꿔야 하나요? 점진적으로 바꾸세요. 새 코드는 let/const만 사용하며, 기존 코드는 수정할 때 함께 바꾸면 됩니다.

관련 글


실전 체크리스트

변수 선언 체크리스트

  • 기본적으로 const 사용
  • 재할당 필요 시 let 사용
  • var 사용 금지
  • ESLint no-var 규칙 활성화
  • 객체/배열도 const 사용 (참조 불변)

코드 리뷰 체크리스트

  • var 사용 여부 확인
  • let인데 재할당이 없으면 const로 변경
  • 루프 변수는 let 사용
  • 전역 변수 최소화

키워드

JavaScript, var, let, const, 변수 선언, 스코프, 호이스팅, TDZ, 재할당, 블록 스코프, 함수 스코프, 비교


같이 보면 좋은 글 (내부 링크)

이 주제와 연결되는 다른 글입니다.


이 글에서 다루는 키워드 (관련 검색어)

JavaScript, var, let, const, 변수, 스코프, 호이스팅, 비교 등으로 검색하시면 이 글이 도움이 됩니다.