let, const와 블록 스코프
우리는 7장 "자바스크립트 심화 II"를 통해 자바스크립트의 깊은 내부 동작 원리부터 고급 비동기 처리, 모듈 시스템, 디자인 패턴에 이르기까지 폭넓은 지식을 쌓았습니다. 이제 여러분은 기본적인 웹 애플리케이션을 개발할 수 있는 역량을 갖추었을 것입니다. 하지만 자바스크립트는 ECMAScript라는 표준을 통해 매년 새로운 기능들이 추가되며 발전하고 있습니다.
특히 2015년에 발표된 ES2015 (ES6) 는 자바스크립트에 엄청난 변화를 가져온 버전입니다. 단순히 문법적 설탕을 넘어, 언어의 핵심적인 동작 방식과 개발자 경험을 크게 개선하는 많은 기능들이 추가되었습니다. 이 외에도 매년 ECMAScript는 새로운 기능들을 도입하며 더욱 강력하고 유연한 언어로 진화하고 있습니다.
8장 "최신 ECMAScript 기능"에서는 현대 자바스크립트 개발에서 필수적으로 사용되는 ES2015 이후의 주요 문법과 개념들을 집중적으로 다룹니다. 이 기능들을 익히는 것은 여러분의 코드를 더욱 간결하고 효율적이며, 가독성 높게 만드는 데 큰 도움이 될 것입니다.
오랜 기간 자바스크립트에서 변수를 선언하는 유일한 방법은 var
키워드였습니다. var
는 유연했지만, 동시에 많은 혼란과 잠재적인 버그를 유발하는 몇 가지 특성을 가지고 있었습니다. ES2015(ES6)에서 도입된 let
과 const
키워드는 이러한 var
의 문제점을 해결하고, 자바스크립트의 변수 선언 방식을 더욱 예측 가능하고 안전하게 만들었습니다. 이와 함께 중요한 개념인 블록 스코프(Block Scope) 가 등장했습니다.
이번 장에서는 var
의 문제점을 되짚어보고, let
과 const
의 특징, 그리고 자바스크립트의 스코프 개념을 깊이 있게 이해하는 시간을 가지겠습니다.
var
키워드의 문제점 (복습 및 심화)
var
는 함수 스코프를 따르며, 몇 가지 독특한 동작 때문에 개발자에게 혼란을 주거나 의도치 않은 버그를 발생시키기 쉬웠습니다.
-
함수 스코프 (Function Scope):
var
로 선언된 변수는 오직 함수 내부에서만 지역 변수로 취급되며,if
문이나for
문과 같은 블록 내부에서는 지역 변수로 취급되지 않고 해당 함수의 스코프(또는 전역 스코프)에 속하게 됩니다.if (true) { var x = 10; console.log(x); // 결과: 10 } console.log(x); // 결과: 10 (if 블록 밖에서도 접근 가능) function introduce() { var name = "김철수"; console.log(name); // 결과: 김철수 } introduce(); // console.log(name); // ReferenceError: name is not defined (함수 스코프)
이는 다른 언어에서 블록 스코프가 일반적인 것과 달라 혼란을 야기했습니다.
-
변수 호이스팅 (Variable Hoisting):
var
로 선언된 변수는 선언부가 스코프의 최상단으로 끌어올려진 것처럼 동작합니다. 할당은 원래 위치에서 이루어지지만, 선언만 먼저 처리됩니다. 이 때문에 변수를 선언하기 전에 참조해도 오류가 발생하지 않고undefined
가 출력됩니다.console.log(myVar); // 결과: undefined var myVar = "hello"; console.log(myVar); // 결과: hello // 실제로는 다음과 같이 동작합니다: // var myVar; // console.log(myVar); // myVar = "hello"; // console.log(myVar);
이는 코드를 예측하기 어렵게 만들고 잠재적인 버그의 원인이 됩니다.
-
변수 재선언 허용:
var
는 동일한 이름의 변수를 여러 번 재선언해도 오류를 발생시키지 않습니다.var myName = "Alice"; console.log(myName); // 결과: Alice var myName = "Bob"; // 동일한 이름으로 재선언해도 에러 없음 console.log(myName); // 결과: Bob
이는 실수로 기존 변수를 덮어쓸 위험이 있어 대규모 프로젝트에서 버그를 유발할 수 있습니다.
이러한 var
의 문제점들은 자바스크립트 개발을 어렵게 만드는 주요 원인이었습니다.
let
키워드: 새로운 변수 선언의 시작
let
키워드는 var
의 문제점을 해결하기 위해 도입된 변수 선언 방식입니다.
블록 스코프 (Block Scope)
let
으로 선언된 변수는 선언된 블록({}
) 안에서만 유효합니다. 블록은 함수, if
문, for
문, while
문 등의 중괄호로 둘러싸인 영역을 의미합니다.
let y = 100; // 전역 스코프 또는 상위 블록 스코프
if (true) {
let z = 20; // if 블록 내부에서만 유효
console.log(z); // 결과: 20
console.log(y); // 결과: 100 (상위 스코프 변수는 접근 가능)
}
// console.log(z); // ReferenceError: z is not defined (블록 밖에서 접근 불가)
for (let i = 0; i < 3; i++) {
console.log(i); // 결과: 0, 1, 2
}
// console.log(i); // ReferenceError: i is not defined (for 블록 밖에서 접근 불가)
블록 스코프는 코드를 더 예측 가능하게 만들고, 변수 이름 충돌의 위험을 줄여줍니다.
변수 재선언 불가능
let
은 동일한 스코프 내에서 같은 이름의 변수를 재선언하는 것을 허용하지 않습니다.
let fruit = "사과";
// let fruit = "바나나"; // SyntaxError: 'fruit' has already been declared
이는 개발자의 실수를 방지하고 코드의 견고성을 높여줍니다.
변수 호이스팅과 TDZ
let
변수도 호이스팅되지만, var
와 다르게 초기화되기 전까지는 접근할 수 없습니다. 이 영역을 TDZ (Temporal Dead Zone, 시간상 사각 지대) 라고 부릅니다. TDZ에 있는 변수에 접근하려고 하면 ReferenceError
가 발생합니다.
console.log(myLetVar); // ReferenceError: Cannot access 'myLetVar' before initialization
let myLetVar = "hello";
console.log(myLetVar); // 결과: hello
TDZ는 개발자가 변수를 선언하기 전에 사용하는 실수를 방지하여 코드의 안정성을 높입니다.
키워드: 상수 선언
const
키워드는 let
과 마찬가지로 블록 스코프를 따르며, 변수 호이스팅과 TDZ의 특성도 공유합니다. 하지만 가장 중요한 차이점은 상수(constant)를 선언할 때 사용된다는 것입니다. 즉, 한 번 할당된 값을 변경할 수 없습니다.
재할당 불가능
const
로 선언된 변수는 선언과 동시에 값을 할당해야 하며, 이후에는 재할당이 불가능합니다.
const PI = 3.14159;
console.log(PI); // 결과: 3.14159
// PI = 3.14; // TypeError: Assignment to constant variable. (재할당 불가능)
// const TAX_RATE; // SyntaxError: Missing initializer in const declaration (선언과 동시에 할당 필수)
객체/배열과 const
const
가 재할당을 금지한다는 것은 변수가 가리키는 메모리 주소(참조)를 변경할 수 없다는 의미입니다. 객체나 배열과 같은 참조 타입의 경우, const
로 선언해도 객체/배열 내부의 프로퍼티나 요소는 변경할 수 있습니다.
const user = {
name: "Jane",
age: 25
};
user.age = 26; // 객체 내부의 프로퍼티 변경은 가능
console.log(user.age); // 결과: 26
// user = { name: "Mike", age: 30 }; // 하지만 객체 자체를 재할당하는 것은 불가능
// TypeError: Assignment to constant variable.
const colors = ["red", "green"];
colors.push("blue"); // 배열에 요소 추가는 가능
console.log(colors); // 결과: ["red", "green", "blue"]
// colors = ["yellow"]; // 배열 자체를 재할당하는 것은 불가능
// TypeError: Assignment to constant variable.
객체나 배열 내부까지도 변경 불가능하게 만들려면, 깊은 복사(deep copy)를 사용하거나 Object.freeze()
와 같은 메서드를 활용해야 합니다.
var
vs let
vs const
현대 자바스크립트 개발에서는 다음과 같은 규칙을 따르는 것이 일반적입니다.
- 기본적으로
const
를 사용합니다.- 변수의 값이 변경될 일이 없는 상수나, 참조할 객체/배열이 재할당될 일이 없는 경우에 사용합니다.
- 이는 코드의 의도를 명확히 하고, 잠재적인 버그를 줄이는 데 큰 도움이 됩니다.
- 재할당이 필요한 경우에만
let
을 사용합니다.- 반복문 내의 카운터 변수, 조건에 따라 값이 변경될 수 있는 변수 등에 사용합니다.
var
는 더 이상 사용하지 않는 것을 권장합니다.- 레거시 코드(오래된 코드)를 유지보수하는 경우가 아니라면
var
를 새로운 코드에서 사용하는 것은 피하는 것이 좋습니다.
- 레거시 코드(오래된 코드)를 유지보수하는 경우가 아니라면
모범 사례
// 전역 설정값, 절대 변하지 않는 값
const API_URL = "https://api.example.com";
const MAX_ITEMS_PER_PAGE = 20;
// 한 번 할당되면 변하지 않는 참조형 값 (내부 변경은 가능)
const config = {
theme: "dark",
version: "1.0.0"
};
config.theme = "light"; // 가능
let counter = 0; // 값이 증가해야 하므로 let
for (let i = 0; i < 5; i++) { // 반복문 카운터는 let
counter += i;
}
if (someCondition) {
let result = "Success"; // if 블록 내에서만 필요한 변수는 let
console.log(result);
}
// console.log(result); // 에러
마무리하며
이번 장에서는 자바스크립트에서 변수를 선언하는 새로운 표준인 let
과 const
키워드, 그리고 그와 함께 도입된 블록 스코프(Block Scope) 개념에 대해 심도 있게 학습했습니다.
여러분은 var
키워드가 가졌던 함수 스코프, 변수 호이스팅, 재선언 허용 등의 문제점들을 이해했으며, let
과 const
가 어떻게 블록 스코프, 재선언 불가능, 그리고 TDZ(Temporal Dead Zone)를 통해 이러한 문제점들을 해결하고 코드의 예측 가능성과 안정성을 높이는지 알아보았습니다. 또한, const
가 참조형 값의 내부 변경을 허용한다는 중요한 특징도 파악했습니다.
현대 자바스크립트 개발에서는 var
대신 let
과 const
를 사용하는 것이 강력히 권장됩니다. const
를 기본으로 사용하고, 재할당이 필요한 경우에만 let
을 사용하는 습관을 들이는 것이 좋습니다. 이 새로운 변수 선언 방식은 여러분의 자바스크립트 코드를 더욱 견고하고 가독성 높게 만들어 줄 것입니다.