var, let, const는 모두 변수 선언 키워드로, 중복 선언 허용, 스코프, 호이스팅 관점에서 비교해보면 아래와 같음
var | let | const | |
---|---|---|---|
중복 선언 허용 | O | X | X |
스코프 | 함수 스코프 | 블록 스코프 | 블록 스코프 |
호이스팅 | undefined | 참조 오류 | 참조 오류 |
var 키워드를 사용해서 선언한 변수는 중복 선언이 가능
var x = 1;
var y = 1;
var x = 100;
// 이 때 초기화 문이 없는 변수 선언문은 무시됨
var y;
console.log(x); // 100
console.log(y); // 1
하지만 let으로 선언한 변수는 같은 스코프 내에서 재선언하려고 하면 문법 오류가 발생함
let x = 123;
let x = 456; // SyntaxError : Identifier 'x' has already been declared
const도 마찬가지로 재선언 하려고 하면 오류가 발생함.
let과의 차이점은 반드시 선언과 동시에 초기화해야 한다는 점과 재할당도 불가능하다는 점!
const x; // SyntaxError : Missing initializer in const declaration
var 키워드로 선언한 변수는 함수의 코드 블록만 지역 스코프로 인정함
그래서 함수 외부에서 var키워드로 선언한 변수는 코드 블록 내에서 선언해도 전역변수가 됨
var i = 1;
for (var i=0; i<5; i++) {
// 동작
}
console.log(i) // 5
위와 같이 조건문이나 반복문에 의해 의도치 않게 값이 변경될 수 있음
하지만 let의 경우 모든 코드 블록(함수, if문, for문, while문, try/catch문 등)을 지역 스코프로 인정하는 블록 레벨 스코프를 따름
let x = 1;
{
let x = 2;
let y = 3;
}
console.log(x); // 1
console.log(y); // ReferenceError: y is not defined
const도 마찬가지로 블록 레벨 스코프를 가짐
var 키워드로 변수를 선언하면 변수 호이스팅에 의해 변수 선언문이 스코프 선두로 끌어 올려진 것 처럼 동작함
(할당문은 끌어올려지는게 아니기 때문에 할당 이전에 참조하면 undefined로 할당되어있는 걸 볼 수 있음)
console.log(x); // undefined
x = 1;
console.log(x); // 1
var x; // 이 선언문이 가장 먼저 실행되어서 undefined로 초기화 됨
하지만 let, const 키워드로 선언한 변수의 경우, 변수 호이스팅이 발생하지 않는 것 처럼 동작함
console.log(x); // ReferenceError : x is not defined
let x;
초기화 단계 이전에 변수에 접근하려고 하면 참조 오류가 발생하는데
즉, 선언 단계는 호이스팅되는데 var 키워드로 선언하면 undefined로 초기화도 함께 되기 때문에 참조하려고 하면 undefined가,
let, const 키워드로 선언하면 선언 단계와 초기화 단계는 따로 진행되기 때문에 선언 단계와 초기화단계 사이의 일시적 사각지대에서 참조하려고 하기 때문에 오류가 발생함
=> 호이스팅이 발생하지 않는 것 처럼 보임
let x = 1;
{
console.log(x); // ReferenceError : Cannot access 'x' before initialization
let x = 2;
}
그래서 만약 위 코드에서도 전역변수를 참조해서 1을 출력할 것 같지만, 블록 내에서 x가 선언되었기 때문에 호이스팅되어 참조 에러가 발생함