
var만 사용할 수 있었다. 하지만 var은 다음과 같은 문제점들을 가지고 있어 현대 Javascript에서는 지양해야 한다.
- 예측 불가능한 스코프 : 함수 스코프만을 가져 블록 레벨의 스코프 제어가 불가능
- 의도치 않은 전역 객체 생성 : 함수 외부에서 선언 시 전역 객치(window, global)의 속성이 됨
- 중복 선언 허용 : 같은 변수를 여러 번 선언해도 에러가 발생하지 않음
- 호이스팅으로 인한 혼란 : 선언 전에도 접근 가능한 동작이 코드의 흐름을 예측하기 어렵게 함
// 재선언 가능
var name = "이름";
var name = "이름2"; // 중복 선언 가능 - 버그 발생 위험
console.log(name); // '이름2'
// 호이스팅(선언과 할당이 분리. 선언만 끌어올려지고, 할당은 원래 위치에서 실행)
console.log(foo); // undefined - 호이스팅으로 인한 혼란
var foo = '안녕';
// 위코드는 내부적으로 다음과 같이 실행 됨
var foo; // 호이스팅
console.log(foo); // undefined
foo = "안녕"; // 초기화
이런 특징들 때문에 예상치 못한 버그가 발생하기 쉬웠다. 특히 큰 규모의 프로젝트에서는 변수가 어디서 어떻게 사용될지 추적하기가 매우 어려웠다.
ES2015에서 도입된 let과 const가 이러한 문제점들을 해결했다.
// 1. 재선언 불가
let name = "이름1";
let name = "이름2"; // SyntaxError: 중복 선언 방지
// 2. 재할당 가능
let name = "이름1";
name = "이름2";
name = "이름3";
console.log(name); // '이름3'
// 3. 선언만 따로 가능
let name;
name = "이름1";
console.log(name); // '이름1'
// 1. 재선언 불가
const name = "이름";
const name = "이름2"; // SyntaxError: Identifier 'name' has already...
// 2. 재할당 불가
const name = "이름";
name = "이름2"; // TypeError: Assignment to constant variable
// 3. 선언과 동시에 초기화 필수
const name; // SyntaxError: Missing initializer in const declaration
// 1. var는 함수 스코프
function example(){
var x = 1;
if (true){
var x = 2; // if는 블록이라 함수스코프를 가진 var는 상위에 있는 x를 재할당
console.log(x); // 2
}
console.log(x); // 2
}
// 2. let, const는 블록 스코프
function example(){
let x = 1;
if (true){
let x = 2; // let, const는 블록스코프를 가져서 새로운 지역변수를 생성
console.log(x); // 2
}
console.log(x); // 1
}
let과 const는 TDZ라는 특별한 특성을 가진다. TDZ는 '일시적 사각지대'라고 직역할 수 있고 선언문이 실행되기 전까지는 어떤 방법으로도 접근할 수 없다.
먼저 var를 사용했을 때를 봐보자
console.log(name); // undefined
var name = '이름';
선언되기 전에도 접근이 가능하다. 하지만 let이나 const를 사용하면?
console.log(name); // ReferenceError: Cannot access 'name' before initialization
let name = '이름';
에러가 발생한다. 이게 바로 TDZ의 영향이다.
왜 이런 차이가 있을까? 🧐
var의 경우
- 호이스팅 발생 시 undefined로 자동 초기화
- 어디서든 접근 가능(제한 없음)
let, const의 경우
- 호이스팅은 되지만 초기화 전까지는 TDZ에 갇힘
- 변수 선언 전에 접근하면 에러 발생
TDZ가 왜 필요할까? 🌟
- 버그 예방 : 변수 선언 전 사용 방지
- 코드 품질 : 더 명확하고 예측 가능한 코드 작성 가능
- 안정성 : 의도치 않은 변수 사용 방지
var x = 1;
// ... 1000줄의 코드가 있다고 가정
var x = 2; // 어디서 값이 변경되었는지 추적하기 어려움
function badExample(){
for (var i = 0; i < 5; i ++){
// i는 함수 전체에서 접근 가능
}
console.log(i); // 루프 밖에서도 i에 접근 가능 - 의도치 않은 동작
}
for (var i = 0; i < 3; i ++){
setTimeout(()=> console.log(i), 1000)
// 3, 3, 3 출력
// 함수스코프라서 3번의 루프 모두 같은 i 를 바라봄
// let을 사용하면 반복마다 새로운 i가 만들어져서 1, 2, 3 출력
}
var global = '전역변수'
console.log(window.global); // 브라우저 전역 객체 오염
- 기본적으로
const사용- 재할당이 필요한 경우에만
let사용var는 레거시 코드가 아니라면 사용하지 않기- React나 Next에서 컴포넌트 상태관리 할 때는 주로
const사용