변수 선언 방식은 var, let, const 3가지가 있는데 var 로 선언이 가능했는데 왜 const 와 let 이 나오고
var은 이제 더 이상 권장하지 않는 것일까?
var 키워드로 선언한 변수의 문제점
1) var키워드로 선언한 변수는 중복 선언이 가능하다.
var x=1;
var y=1;
//var키워드로 선언된 변수는 같은 스코프 내에서 중복 선언을 허용
//초기화 문이 있는 변수 선언문은 자바스크립트 엔진에 의해 var키워드가 없는 것처럼 동작
var x=100;
var y;//초기화문이 없으므로 이 변수 선언문은 무시됨
console.log(x);//100
console.log(y);//1
이 예제의 var 키워드로 선언한 x변수와 y변수는 중복 선언되었다. 이처럼 var 키워드로 선언한 변수를 중복 선언하면 초기화 유무에 따라
다르게 동작한다. 초기화 문이 있는 변수 선언은 자바스크립트 엔진에 의해 var 키워드가 없는 것처럼 동작하고 초기화문이 없는 변수 선언문은 무시된다.
만약 동일한 이름의 변수가 이미 선언되어 있는 것을 모르고 변수를 중복 선언하면서 값까지 할당했다면 의도치 않게 먼저 선언된 변수 값이 변경되는 부작용이 발생한다.
2) var 키워드로 선언한 변수는 오로지 함수의 코드 블록만을 지역 스코프로 인정한다. 따라서 함수 외부에서 var키워드로 선언한 변수는 코드 블록 내에서 선언해도 모두 전역 변수가 된다.
var x=1;
if(true){
//x는 전역 변수다. 이미 선언된 전역 변수 x가 있으므로 x변수는 중복 선언된다.
//이는 의도치 않게 변수값이 변경되는 부작용을 발생시킴
var x=10;
}
console.log(x);//10
3) 변수 선언문 이전에 변수를 참조하면 언제나 undefined를 반환한다.
변수 호이스팅이란?
: 변수 선언문이 스코프의 선두로 끌어올려지는 현상
var 키워드로 변수를 선언하면 변수 호이스팅에 의해 변수 선언문이 스코프의 선두로 끌어 올려진 것처럼 동작한다. 즉, 변수 호이스팅에 의해 var 키워드로 선언한 변수는 변수 선언문 이전에 참조할 수 있다. 단, 할당 이전에 변수를 참조하면 언제나 undefined를 반환한다.
//이 시전에서 변수 호이스팅에 의해 이미 foo변수가 선언되었다. (1.선언단계)
//변수 foo는 undefined로 초기화 된다 (2.초기화단계)
console.log(foo);
//변수에 값을 할당 (3. 할당 단계)
foo=123;
console.log(foo);//123
//변수 선언은 런타임 이전에 자바스크립트 엔진에 의해 암묵적으로 실행된다!!!
var foo;
변수 선언문 이전에 변수를 참조하는 것은 변수 호이스팅에 의해 에러를 발생시키지는 않지만 프로그램의 흐름상 맞지 않을 뿐더러 가독성을 떨어뜨리고 오류를 발생시킬 여지를 남긴다.
var, let, const의 차이점
var의 문제점을 해결하기 위해 나온 let 과 const는 var의 세가지 문제점을 해결하였다.
1. 변수 중복 선언 불가
1) let
let 키워드로는 변수 중복 선언(재선언)이 불가하지만, 재할당은 가능하다.
let name = 'kmj'
console.log(name) // output: kmj
let name = 'howdy' // output: Uncaught SyntaxError: Identifier 'name' has already been declared
name = 'howdy'
console.log(name) // output: howdy
2) const
const 가 let 과 다른 점은 반드시 선언과 초기화를 동시에 해야한다
const 는 let과 마찬가지로 재선언이 불가하며 let 과 달리 재할당도 불가능하다.
재할당의 경우 원시값은 불가능하지만, 객체는 가능하다. const는 재할당을 금지할 뿐, 불변을 의미하지는 않는다.
// 원시값의 재할당
const name = 'kmj'
name = 'howdy' // output: Uncaught TypeError: Assignment to constant variable.
// 객체의 재할당
const name = {
eng: 'kmj',
}
name.eng = 'howdy'
console.log(name) // output: { eng: "howdy" }
2. 블록 레벨 스코프
let, const 키워드로 선언한 변수는 모두 코드 블록(ex. 함수, if, for, while, try/catch 문 등)을 지역 스코프로 인정하는 블록 레벨 스코프를 따른다.
let a = 1
if (true) {
let a = 5
}
console.log(a) // output: 1
var 키워드로 선언한 경우 5가 나왔지만, let 키워드로 선언한 경우 if 문 안에 있는 것은 지역 스코프를 가져 전역에서 console을 찍었을 경우, 전역에 있는 a가 결과 값으로 출력된다. (const 키워드도 let 키워드와 동일하게 동작한다)
3. 변수 호이스팅
(1) let
let 키워드로 선언한 변수는 선언 단계와 초기화 단계가 분리되어 진행된다. 즉, 런타임 이전에 자바스크립트 엔진에 의해 선언 단계가 먼저 실행되지만, 초기화 단계가 실행되지 않았을 때 해당 변수에 접근하려고 하면 참조 에러가 뜬다.
console.log(name) // output: Uncaught ReferenceError: name is not defined
let name = 'kmj'
따라서 let 키워드로 선언한 변수는 스코프의 시작 지점부터 초기화 단계 시작 지점까지 변수를 참조할 수 없는 일시적 사각지대(Temporal Dead Zone: TDZ) 구간에 존재한다.
(2) const
const 키워드는 선언 단계와 초기화 단계가 동시에 진행된다.
console.log(name) // output: Uncaught ReferenceError: Cannot access 'name' before initialization
const name = 'kmj'
let 키워드로 선언한 경우, 런타임 이전에 선언이 되어 자바스크립트 엔진에 이미 존재하지만 초기화가 되지 않았기 때문에 name is not defined라는 문구가 떴다. 하지만 const 키워드로 선언한 경우, 선언과 초기화가 동시에 이루어져야 하지만 런타임 이전에는 실행될 수 없다. 따라서 초기화가 진행되지 않은 상태이기 때문에 Cannot access 'name' before initialization 에러 문구가 뜬다.
결론
변수의 스코프는 최대한 좁게, var 보다는 let 과 const 사용을 권장
& 변경되지 않는 값이라면 let보다는 const를 사용할 것