TL;DR
var
- 중복 선언 허용
- 함수 스코프(Function Scope)
- 호이스팅(Hoisting)
- ES6 이전 구식(Old-school)
let
- 중복 선언 방지
- 블록 스코프(Block Scope)
- 호이스팅(Hoisting)과 TDZ(Temporal Dead Zone)
- ES6+
const
- 재할당 금지 및 중복 선언 방지
- 블록 스코프(Block Scope)
- 호이스팅(Hoisting)과 TDZ(Temporal Dead Zone)
- ES6+
스코프
스코프란
- Scope는 변수, 함수가 유효한 범위를 말합니다. 어디에서 정의되고 어디까지 접근 가능한지를 결정하는 데 var의 함수 스코프와 let, const의 블록 스코프로 나뉩니다.
함수 스코프
- var로 선언된 변수는 함수 스코프를 따르며, var로 선언된 변수는 해당 변수가 정의된 함수영역 전체에서 유효하게 동작합니다.
- 함수 내부에서 선언된 모든 변수는 함수의 처음부터 끝까지 접근 가능하며, 함수 외부에서는 해당 변수를 사용할 수 없습니다.
- 그런데 함수 전체에서 유효하기 때문에, 함수 내의 코드 블록 내에서 선언되더라도 함수 전역에서 접근 가능합니다.
- 이는 코드 블록이 많아질수록 관리가 복잡해지고, 의도하지 않은 변수의 재할당이나 중복 선언이 발생할 위험이 있습니다.
function scopeIssue() {
if (condition) {
var four = 4;
}
console.log(four);
}
scopeIssue();
블록 스코프
- let, const 등으로 선언된 변수는 블록 스코프를 따르며, 중괄호 {} 코드 블록 내에서만 해당 변수가 유효하게 동작합니다.
- 즉 if, for, while 등 제어 구조나 일반적인 코드 블록 {} 내에서만 변수가 유효하게 정의되고, 블록 외부에서는 접근할 수 없습니다.
- 아래 코드와 같이 반복문 블록 내에서만 유효하며 반복문 외부에서 i에 접근할 수 없는 것이 var의 함수 스코프와 다른 점입니다.
for (let i = 0; i < 5; i++) {
console.log(i);
}
console.log(i);
- 이는 특정 블록 내에서만 변수가 유효하므로 가독성이 향상되며, 이에 따라 변수 재할당이나 중복 선언 문제를 줄여줍니다.
차이점
| 함수 스코프 (Function Scope) | 블록 스코프 (Block Scope) |
---|
범위 | 함수 내에서만 변수 유효 | 코드 블록 {} 내에서만 변수 유효 |
키워드 | var | let, const |
유효 범위 | 함수 내 선언된 변수는 함수 전체에서 유효함 | 블록 내 선언된 변수는 블록 내에서만 유효 |
중복 선언 | 같은 함수 내에서 중복 선언 가능 (덮어쓰기) | 같은 블록 내에서 중복 선언 불가 |
호이스팅
호이스팅이란
- Hoisting은 JavaScript에서 변수나 함수의 선언이 해당 스코프의 상단으로 끌어올려지는 동작으로, 해당 스코프 내에서 미리 인식됨을 의미합니다.
- 호이스팅에는 변수 호이스팅과 함수 호이스팅이 있지만 여기에서는 변수 호이스팅에 대해서 이야기 하겠습니다.
var의 호이스팅
- var의 선언은 스코프 최상단으로 끌어올려지지만, 초깃값은 끌어올려지지 않으므로 undefined가 출력됩니다.
console.log(five);
var five = 5;
var five;
console.log(five);
five = 5;
let, const의 호이스팅
- let과 const 모두 호이스팅되지만 아래 설명할 TDZ(Temporal Dead Zone)으로 인해 선언 이전에 변수를 사용할 수 없게 됩니다.
- 선언 전에 해당 변수에 접근하면 참조에러(ReferenceError)가 발생합니다.
console.log(six);
let six = 6;
TDZ(Temporal Dead Zone)
TDZ란
- let, const 변수가 실제로 사용할 수 있을 때까지(즉 선언된 변수가 초기화되기 전 까지)의 구간(영역)을 TDZ라고 합니다.
- TDZ 구간에서 해당 변수를 참조하면 참조에러(ReferenceError)가 발생합니다.
동작 원리
- let과 const는 위에서 말한바와 같이 호이스팅되지만, var과 다르게 변수가 선언된 시점에서 스코프 내에서 사용할 수 있습니다. 선언 전에 접근하려고 하면 TDZ 때문에 에러가 발생합니다.
- TDZ로 인해 선언부터 실제 초기화 구간 이전에 변수를 사용할 수 없도록 보호하는 역할을 합니다.
목적
- 코드에서 변수를 선언하기 전에 사용하는 실수를 방지하기 위해 존재합니다.
- var에서는 호이스팅되면서 초기화 이전에 사용해도 Error가 아닌 undefined를 반환하므로 잠재적으로 문제가 발생할 수 있습니다.
- 그러나 let, const에서는 TDZ의 존재로 인해 변수 선언 이전에 실수로 변수를 참조하지 않도록 하여 더 안전한 코드 작성을 도와줍니다.
결론
var: 더 이상 사용하지 마세요
- var는 ES6 이전까지 사용되었습니다. ES6 이전 브라우저를 고려해야 하는 경우가 아니라면 배제해야 합니다. 즉 var는 이제 구식으로 간주되며 새로 작성하는 코드에는 사용을 지양합시다.
- 함수 스코프와 호이스팅 특성으로 예기치 않은 동작을 일으킬 수 있습니다.
- 중복 선언이 가능하므로 복잡한 코드 환경에서 버그를 일으키기 쉽습니다.
- 선언만 호이스팅되고 초기화는 그대로 유지되어서 선언 전에 사용하더라도 ReferenceError 없이 undefined가 반환되므로 예기치 않은 동작이 발생할 수 있습니다.
let: 재할당이 필요한 경우 사용하세요
- let은 값을 재할당해야 할 때 사용해야 합니다.
- 예를 들어 for 반복문의 인덱스나, 함수 내부에서 변하는 값을 저장하는 경우 사용하는 것이 좋습니다.
- 블록 스코프이므로 해당 코드 블록에서만 유효하게 유지해야 할 때 사용합니다.
- 호이스팅이 발생하더라도 TDZ로 인해 let은 변수 선언 이후 유효하게 접근할 수 있으므로 안전한 코드 작성에 도움을 줍니다.
const: 거의 모든 경우 사용하세요
- const는 변수의 값이 변하지 않아야 할 때(값이 재할당되지 않을 때) 사용해야 합니다.
- 예를 들면 코드에서 상수값(PI 등)이나 안전하게 참조형 타입 데이터(객체, 배열 등)를 변수에 저장하는 경우 사용하는 것이 좋습니다.
- let과 마찬가지로 블록 스코프이므로 해당 코드 블록에서만 유효하게 유지해야 할 때 사용합니다.
- 마찬가지로 호이스팅이 발생하더라도 TDZ로 인해 const는 변수 선언 이후 유효하게 접근할 수 있으므로 안전한 코드 작성에 도움을 줍니다.
- const는 거의 모든 경우에 사용하고, 값이 변해야 하는 부분에는 let을 사용하세요.
참고자료
- Flanagan, D. (2022). 자바스크립트 완벽 가이드(7판). 인사이트.
- 이웅모. (2020). 모던 자바스크립트 Deep Dive : 자바스크립트의 기본 개념과 동작 원리. 위키북스.
- 정재남. (2019). 코어 자바스크립트 : 핵심 개념과 동작 원리로 이해하는 자바스크립트 프로그래밍. 위키북스.
- 모던 Javascript 튜토리얼 - 오래된 var
이글은 종종 다시 와서 봐야겠어요. 변수 정리 한방에 되네요. 굿!