ES5 까지 변수를 선언할 수 있는 유일한 방법은 var 키워드를 사용하는 것이었다. var 키워드로 선언된 변수는 아래와 같은 특징이 있다.
함수 레벨 스코프(Function-level scope)
함수의 코드 블록만을 스코프로 인정한다. 따라서 전역 함수 외부에서 생성한 변수는 모두 전역 변수이다. 이는 전역 변수를 남발할 가능성을 높인다.
for 문의 변수 선언문에서 선언한 변수를 for 문의 코드 블록 외부에서 참조할 수 있다.
var 키워드 생략 허용
암묵적 전역 변수를 양산할 가능성이 크다.
변수 중복 선언 허용
의도하지 않은 변수값의 변경이 일어날 가능성이 크다.
변수 호이스팅
변수를 선언하기 이전에 참조할 수 있다.
대부분의 문제는 전역 변수로 인해 발생한다. 전역 변수는 간단한 애플리케이션의 경우, 사용이 편리하다는 장점이 있지만 불가피한 상황을 제외하고 사용을 억제해야 한다. 전역 변수는 유효 범위(scope)가 넓어서 어디에서 어떻게 사용될 것인지 파악하기 힘들며, 비순수 함수(Impure function)에 의해 의도하지 않게 변경될 수도 있어서 복잡성을 증가시키는 원인이 된다. 따라서 변수의 스코프는 좁을수록 좋다.
- 출처 : https://poiemaweb.com/
그리하여 ES6는 이러한 var 키워드의 단점을 보완하기위해 let, const을 도입하였고, 이 글을 통해 var와 어떠한 차이가 있는지, 왜 사용해야하는지 정리해보겠다.
기존의 var를 통해 선언한 변수는 함수 레벨 스코프(Function-level scope)를 참조했지만, let은 대부분의 프로그래밍 언어처럼 블록 레벨 스코프(Block-level scope)를 참조한다.
블록 레벨 스코프를 선언된 변수는 모든 코드 블록(함수, if 문, for 문, while 문, try/catch 문 등) 내에서만 유효하게되는데, 이로인해 코드 블록 외부에서는 참조할 수 없다.
let a = 123; // 전역 변수
{
let a = 456; // 지역 변수
let b = 456; // 지역 변수
}
console.log(a); // 123
console.log(b); // ReferenceError: b is not defined
먼저 첫 라인의 a는 let을 통해 전역변수로 123이란 number를 선언하였다. 그리고 중간에 블록({})안에서 지역변수로 456이란 값을 선언 하였는데, 만일 var로 선언했다면, 하단에서 console.log(a)
로 출력 시 전역 변수로 선언했던 '123'이란 값은 '456'으로 재할당 되었겠지만, let은 블록내에서만 유효 범위를 가지기에, 전역에 존재하는 a의 값이 정상적으로 출력된다.
console.log(a); // undefined
var a;
console.log(b); // Error: Uncaught ReferenceError: b is not defined
let b;
많은 자료에서 let은 호이스팅이 되지않는다고 서술되어있는데, let 또한 호이스팅 된다고한다. 그러나
var
와는 달리 호이스팅에 의해 끌어올려져 'undifend'로 초기화되지않고 끌어올려지되, 선언 전 까지 일시적 사각지대(Temporal Dead Zone)에 빠지게되어 undefined이 아닌 'ReferenceError'가 뜨는 것이다. 즉var
처럼 선언과 초기화가 동시에 이뤄지는것이 아닌, 선언 단계와 초기화 단계가 분리되어 진행된다.
- 출처 : https://poiemaweb.com/
const는 상수를 선언하기 위해 사용되며, 재할당 가능여부를 제외하고는 let과 동일한 특징을 갖고있다.
const a = 123;
a = 456; // TypeError: Assignment to constant variable.
const b; // SyntaxError: Missing initializer in const declaration
const는 let과 달리 재할당이 불가능하기 때문에, 위의 예제에서 볼 수 있듯이 선언 후에는 다른값으로 재할당 시 Assignment to constant variable.
에러가 발생하는것을 알 수 있다. 또한, 선언과 동시에 할당이 이루어져야하는데. 만일 할당을 하지않고 상수명 만을 선언한다면 SyntaxError: Missing initializer in const declaration
라는 에러가 발생 하게된다.
const user = { name: 'Lee' };
user.name = 'Park';
console.log(user); // { name: 'Park' }
const의 한가지 재밌는점은 const로 선언한 객체의 내부 프로퍼티는 재할당이 가능하다는것이다. 물론 객체의 내용이 변경되더라도 객체 타입 변수에 할당된 주소값은 변경되지 않는다. 그렇기에 객체 타입 변수 선언에는 const를 사용하는것이 좋다고한다.