변수 선언문의 차이점
세 가지 종류의 변수 선언문
자바스크립트에서 변수를 처음 정의(또는 설정)하는 것을 "변수를 선언한다"라고 합니다.
변수를 선언하려면 자바스크립트의 규칙에 따라 선언해야 합니다. 자바스크립트에서는 변수를 선언할 때 '변수 선언문(Statement)'으로 합니다.
변수 선언문은 하나만 있는 것이 아니라, 세 가지 종류의 선언문이 있습니다. 아래는 이 세 가지 선언문입니다.
자바스크립트는 이 세 가지 변수 선언문을 제공하여, 개발자가 변수 선언 시 코드의 편리성, 안정성, 충돌 방지, 그리고 예기치 않은 동작을 방지할 수 있도록 선택할 수 있게 합니다.
각각의 변수 선언문의 특징과 차이점을 이해하는 것은 자바스크립트 개발에서 매우 중요합니다.
var, let, const의 차이점을 '초기화', '스코프',' 재선언 및 재할당', '호이스팅' 측면에서 비교하여, 각 선언문이 어떤 상황에서 적합한지 한눈에 파악할 수 있도록 설명할 것입니다. 마지막으로 '자바스크립트 변수 선언 방법과 스코프의 중요성'에 대해 언급합니다.
초기화(Initialization)
자바스크립트에서 변수가 선언될 때 값을 할당하는 과정을 "초기화"라고 합니다.
var나 let으로 으로 선언한 변수는 선언 시 값을 할당해도 되고, 하지 않아도 됩니다. 값을 할당하지 않으면 참조 시 자바스크립트 엔진이 자동으로 undefined를 할당됩니다.
반면, const는 선언과 동시에 반드시 초기화를 해야 하며, 값을 할당하지 않으면 에러가 발생합니다.
예제
var
var a = 10;
console.log(a); // 출력: 10
var b;
console.log(b); // 출력: undefined
let
let a = 10;
console.log(a); // 출력: 10
let b;
console.log(b); // 출력: undefined
const
const 선언 - 반드시 초기화해야 함
const age = 30;
const 선언 - 초깃값을 할당하지 않으면 에러
const age; // Uncaught SyntaxError: Missing initializer in const declaration
스코프(Scope)
스코프(Scope)란 '범위' 또는 '영역'을 의미하며 여기에서는 변수나 함수에 접근할 수 있는 유효한 코드의 영역을 의미합니다.
| 비교 항목 | var |
let |
const |
|---|---|---|---|
| 스코프 | 글로벌(전역) 스코프 또는 함수 스코프를 가짐 | 글로벌(전역) 스코프 또는 블록({}) 스코프를 가짐 |
글로벌(전역) 스코프 또는 블록({}) 스코프를 가짐 |
var
var로 선언된 변수는 글로벌 스코프 또는 함수 스코프를 가집니다.
- 함수 밖에서
var로 선언된 변수는 코드 전체에서 유효한 글로벌(전역) 스코프를 가집니다. - 함수 내에서
var로 선언된 변수는 해당 함수와 하위 함수 내에서 유효한 함수 스코프를 가집니다. if문이나for문 등 모든 블록({})은var로 선언된 변수의 스코프에 아무런 영향을 주지 않습니다.
var로 선언한 변수는 함수 밖에서 선언되었으면 글로벌에서 사용 가능(유효)하고, 함수 내에서 선언되었으면 해당 함수 내에서만 사용 가능(유효)합니다.
let, const
let이나 const로 선언된 변수는 글로벌(전역) 스코프 또는 블록({}) 스코프를 가집니다.
- 블록 밖에서
let이나const로 선언된 변수는 코드 전체에서 유효한 글로벌(전역) 스코프를 가집니다. - 블록 내에서
let이나const로 선언된 변수는 해당 블록과 하위 블록 내에서 유효한 블록 스코프를 가집니다.
let이나 const로 선언한 변수는 블록 밖에서 선언되었으면 글로벌에서 사용 가능(유효)하고, 블록 내에서 선언되었으면 해당 블록 내에서만 사용 가능(유효)합니다.
블록({})의 의미
자바스크립트에서 블록은 중괄호 {}로 둘러싸인 코드 영역을 의미합니다.
다음은 블록의 일반적인 형태들입니다.
if () { // if 블록
// ...
} else { // else 블록
// ...
}
function exampleFn() { // 함수 블록
// ...
}
{ // 임의의 독립적인 블록 (일반적으로 잘 사용되지는 않음)
let temp = 10; // temp는 이 블록 내에서만 유효
}
for () { // for 블록
// ...
}
하지만, 중괄호가 없어도 문법적으로 중괄호가 있어야 하지만 생략된(if 또는 for 문 뒤의 단일 문장) 코드 영역 역시 개념적으로 블록에 해당지만, 실제 블록이 아니기 때문에 let이나 const로 변수를 선언할 수 없습니다.
예제
var
/* 글로벌(전역) 스코프 */
var globalVar = "글로벌 변수"; // 코드 전체 영역에서 유효한 변수임
function exampleFunction() {
/* 함수 스코프 */
var functionVar = "함수 내 변수"; // 함수 내 전체 영역에서 유효한 변수임
if (true) {
var blockVar = "블록 내 변수"; // if 문의 블록({}) 내에서 선언되었지만, 함수 내 전체 영역에서 유효함
console.log(functionVar); // 출력: "함수 내 변수"
console.log(blockVar); // 출력: "블록 내 변수"
}
// if 문의 블록({}) 내에서 선언되었지만, 함수 내 전체 영역에서 유효한지 확인
console.log(blockVar); // 출력: "블록 내 변수"
}
exampleFunction();
console.log(globalVar); // 출력: "글로벌변수"
console.log(functionVar); // ReferenceError 발생(함수 외부에서 유효하지 않음, functionVar is not defined)
let
/* 글로벌(전역) 스코프 */
let globalVar = "글로벌 변수"; // 이 파일(또는 스크립트)의 최상위 블록 전체에서 유효함
function exampleFunction() {
/* 함수 블록 스코프 */
let functionVar = "함수 블록 변수"; // 함수 전체 블록에서 유효함
if (true) {
let innerBlockVar = "if 블록 변수";
console.log(functionVar); // 출력: "함수 블록 변수"
console.log(innerBlockVar); // 출력: "if 블록 변수"
}
// if 블록 스코프 외부이므로 참조 불가
// console.log(innerBlockVar); // ReferenceError (innerBlockVar is not defined)
}
if (true) {
let ifBlockVar = "if 블록 변수";
console.log(ifBlockVar); // 출력: "if 블록 변수"
}
exampleFunction();
console.log(globalVar); // 출력: "글로벌 변수"
// console.log(functionVar); // ReferenceError (functionVar is not defined)
// console.log(ifBlockVar); // ReferenceError (ifBlockVar is not defined)
const
/* 글로벌(전역) 스코프 */
const globalVar = "글로벌 변수"; // 이 파일(또는 스크립트)의 최상위 블록 전체에서 유효함
function exampleFunction() {
/* 함수 블록 스코프 */
const functionVar = "함수 블록 변수"; // 함수 전체 블록에서 유효함
if (true) {
const innerBlockVar = "if 블록 변수";
console.log(functionVar); // 출력: "함수 블록 변수"
console.log(innerBlockVar); // 출력: "if 블록 변수"
}
// if 블록 스코프 외부이므로 참조 불가
// console.log(innerBlockVar); // ReferenceError (innerBlockVar is not defined)
}
if (true) {
const ifBlockVar = "if 블록 변수";
console.log(ifBlockVar); // 출력: "if 블록 변수"
}
exampleFunction();
console.log(globalVar); // 출력: "글로벌 변수"
// console.log(functionVar); // ReferenceError (functionVar is not defined)
// console.log(ifBlockVar); // ReferenceError (ifBlockVar is not defined)
재선언(Redeclaration) 및 재할당(Reassignment)
'재선언'이란 같은 스코프 내에서 동일한 식별자(변수 이름)로 변수를 다시 선언하는것을 말합니다.
'재할당'이란 같은 스코프 내에서 동일한 식별자(변수 이름)로 할당 연산자(=)를 사용하여 변수의 값을 바꾸는 것을 말합니다.
| 비교 항목 | var |
let |
const |
|---|---|---|---|
| 재선언 | 가능 | 불가능 | 불가능 |
| 재할당 | 가능 | 가능 | 불가능 |
예제
var
var로 선언된 변수는 같은 스코프 내에서 재선언(Redeclaration) 및 재할당(Reassignment)이 가능합니다.
이미 var로 선언된 변수의 값을 언제든지 새로운 값으로 변경할 수 있으며, 동일한 식별자(변수 이름)로 변수를 다시 선언해도 오류가 발생하지 않으며, 마지막에 할당된 값으로 덮어쓰게 됩니다.
/* 초기 선언 및 값을 할당 */
var myValue = 10;
console.log(myValue); // 출력: 10
/* 재할당 */
myValue = 20;
console.log(myValue); // 출력: 20 (값이 변경됨)
/* 재선언 (var를 다시 사용) */
var myValue = "Hello";
console.log(myValue); // 출력: "Hello" (오류 없이 다시 선언되고 값이 덮어쓰기 됨)
let
let으로 선언된 변수는 같은 스코프 내에서 재선언(Redeclaration)이 불가합니다.
같은 스코프 내에서 이미 let으로 선언된 변수를 동일한 식별자(변수 이름)로 변수를 다시 선언하면 오류가 발생합니다.
// 같은 스코프 내에서 let 동일한 식별자(변수 이름)로 변수를 다시 선언하면 오류가 발생
let exampleLet = 10;
let exampleLet = 100; // Uncaught SyntaxError: Identifier 'exampleLet' has already been declared
// 서로 다른 스코프 내에서 let 동일한 식별자(변수 이름)로 변수를 다시 선언은 가능
let exampleLet = 10;
console.log(exampleLet); // 출력: 10
if (true) {
let exampleLet = 100;
console.log(exampleLet); // 출력: 100
}
console.log(exampleLet); // 출력: 10
let으로 선언된 변수의 재할당은 변수를 선언한 스코프와 상관없이 접근 가능한 스코프 내에서 동일한 식별자로 변수의 값을 바꿀 수 있습니다.
// 글로벌 스코프
let globalVar = "글로벌 변수";
console.log(globalVar); // "글로벌 변수"
// 재할당 가능
globalVar = "재할당된 글로벌 변수";
console.log(globalVar); // "재할당된 글로벌 변수"
if (true) {
// 블록 스코프
let blockVar = "블록 변수";
console.log(blockVar); // "블록 변수"
// 재할당 가능
blockVar = "재할당된 블록 변수";
console.log(blockVar); // "재할당된 블록 변수"
}
// 블록 밖에서는 참조 불가
// console.log(blockVar); // ReferenceError
const
const로 선언된 변수는 같은 스코프 내에서 재선언(Redeclaration)이 불가합니다.
같은 스코프 내에서 이미 const로 선언된 변수를 동일한 식별자(변수 이름)로 변수를 다시 선언하면 오류가 발생합니다.
// 같은 스코프 내에서 const 동일한 식별자(변수 이름)로 변수를 다시 선언하면 오류가 발생
const exampleConst = 10;
const exampleConst = 100; // Uncaught SyntaxError: Identifier 'exampleConst' has already been declared
// 서로 다른 스코프 내에서 const 동일한 식별자(변수 이름)로 변수를 다시 선언은 가능
const exampleConst = 10;
console.log(exampleConst); // 출력: 10
if (true) {
const exampleConst = 100;
console.log(exampleConst); // 출력: 100
}
console.log(exampleConst); // 출력: 10
const로 선언된 변수의 재할당은 변수를 선언한 스코프와 상관없이 접근 가능한 스코프 내에서 동일한 식별자로 할당 연산자(=)를 사용한 변수의 값을 변경할 수 없습니다.
=)를 사용한 재할당 불가
const exampleConst = 10;
/* 동일한 식별자로 할당 연산자(=)를 사용한 변수의 값을 변경할 수 없습니다. */
exampleConst = 100; // Uncaught TypeError: Assignment to constant variable.
하지만, 변수의 값이 객체나 배열처럼 참조를 저장하는 데이터의 경우에는 속성이나 값을 추가, 업데이트 또는 제거할 수 있습니다.
다음은 const로 할당된 일반 객체(Plain object)의 속성·값 추가, 업데이트, 제거에 대한 예제입니다.
// 일반 객체 선언
const person = {
name: 'Alice',
age: 30
};
// 1. 속성 추가
person.city = 'Seoul'; // 새로운 속성 추가
console.log(person); // 출력: { name: 'Alice', age: 30, city: 'Seoul' }
// 2. 속성 업데이트
person.age = 31; // 기존 속성 값 업데이트
console.log(person); // 출력: { name: 'Alice', age: 31, city: 'Seoul' }
// 3. 속성 제거
delete person.city; // 속성 제거
console.log(person); // 출력: { name: 'Alice', age: 31 }
다음은 const로 할당된 배열의 요소 추가, 업데이트, 제거에 대한 예제입니다.
// 배열 선언
const numbers = [1, 2, 3];
// 1. 요소 추가
numbers.push(4); // 배열 끝에 요소 추가
console.log(numbers); // 출력: [1, 2, 3, 4]
// 2. 요소 업데이트
numbers[0] = 10; // 첫 번째 요소 값 업데이트
console.log(numbers); // 출력: [10, 2, 3, 4]
// 3. 요소 제거
numbers.pop(); // 배열 끝에서 요소 제거
console.log(numbers); // 출력: [10, 2, 3]
호이스팅(Hoisting)
호이스팅이란 자바스크립트에서 변수 및 함수 선언이 스코프의 상단으로 "끌어올려지는" 동작을 말합니다. 즉, 코드의 실행 단계에서 변수나 함수 선언이 실제로 작성된 위치와 상관없이 스코프의 최상단으로 끌어올려지는 현상입니다.
| 비교 항목 | var |
let |
const |
|---|---|---|---|
| 호이스팅 | 발생(단, 변수가 선언된 위치보다 먼저 참조되면 undefined가 할당 됨) |
발생(단, 변수가 선언된 위치보다 먼저 참조되면 에러 발생) | 발생(단, 변수가 선언된 위치보다 먼저 참조되면 에러 발생) |
예제
var
/*
* 아래의 var myName으로 선언된 myName 변수가
* 스코프의 최 상단에 위치한 것처럼 호이스팅 됨
* 다만 선언된 변수만 올라가고,
* 선언 시 할당한 값은 원래 자리에 남게 됨.
*
* 선언 시 할당한 값이 없기 때문에
* 실제 변수가 선언된 위치보다 먼저 참조되면
* undefined로 초기화됩니다.
*/
/* 실제 변수가 선언된 위치보다 먼저 참조 */
console.log(myName); // 출력: undefined (선언만 호이스팅, 값은 undfined로 할당)
/* var로 선언한 변수의 위치 */
var myName = "John";
let, const
let과 const도 호이스팅 됩니다.
다만, 실제 변수가 선언된 위치보다 먼저 참조되면 자바스크립트 엔진은 호이스팅 된 변수가 존재한다는 것을 체크할 수 있습니다. 이 때문에 변수가 선언되기 전에 접근해도 오류가 나지 않기 때문에 변수의 선언 순서가 엄격하게 적용되어야 하는 let과 const에서는 에러를 발생시킵니다.
TDZ(Temporal Dead Zone, 일시적 사각지대)
이렇게 선언된 변수의 스코프 시작점부터 실제 변수가 선언된 위치를 TDZ(Temporal Dead Zone, 일시적 사각지대)라고 합니다. TDZ는 let이나 const로 선언된 변수에만 적용됩니다.
// TDZ 영역 시작
// ↓
console.log(myVar); // ReferenceError: Cannot access 'myVar' before initialization
// ↑
// TDZ 영역 종료
let myVar = 10;
// TDZ 영역 시작
// ↓
console.log(myVar); // ReferenceError: Cannot access 'myVar' before initialization
// ↑
// TDZ 영역 종료
const myVar = 10;
자바스크립트 변수 선언 방법과 스코프의 중요성
- 올바른 변수 선언 방법과 스코프의 이해는 코드의 정확성과 안정성을 보장하는 데 중요합니다.
- 변수의 범위를 명확히 지정하고, 변수의 충돌을 방지하여 예기치 않은 동작을 방지할 수 있습니다.
- 스코프를 제어함으로써 변수의 가시성과 생명주기를 관리할 수 있습니다.
- 변수 선언 방법과 스코프의 올바른 사용은 코드의 가독성, 유지 보수성, 재사용성을 향상시킵니다.
- 효율적인 변수 관리는 개발자의 생산성을 향상시키고 디버깅을 용이하게 만들어줍니다.
따라서, 변수 선언 방법과 스코프에 대한 이해는 자바스크립트 개발에서 필수적이며, 올바르게 활용함으로써 안정적이고 효율적인 코드를 작성할 수 있습니다.
효율적인 자바스크립를 사용하려면 var 변수 선언 방식은 사용하지 마세요!
- 기본적으로 변수의 선언은
const선언 방식을 사용하고, - 변수에 재할당이 필요한 경우에만
let선언 방식으로 사용하시기 바랍니다.
ES6 이상의 자바스크립트를 사용하는 경우에는 var 변수 선언 방식을 피하고 let과 const
를 사용하여 변수를 선언하는 것이 좋습니다. 이를 통해 코드의 가독성과 유지 보수성을 향상시키고 변수 관리에 더욱 신중하게 접근할 수 있습니다.
명세서
| 명세서 사양 | |
|---|---|
| Variable Statement |
ECMAScript® 2026 Language Specification #sec-variable-statement |
호환성
| 문 |
데스크탑 Chrome
|
데스크탑데스크탑 Edge
|
데스크탑 Firefox
|
Safari
|
Node.js
|
|---|---|---|---|---|---|
var
|
1 | 12 | 1 | 1 | 0.10 |
let
|
49 | 14 | 44 | 10 | 6 |
const
|
21 | 12 | 36 | 5.1 | 6 |