var, let, const이 3가지 키워드는 자바스크립트에서 변수를 선언할 때 사용할 수 있다.
let, const는 es6부터 추가된 문법이며 var 이후에 등장했다.
이 글은 각 키워드를 재선언과 재할당, 유효범위 그리고 호이스팅 관점에서 비교하고있다. 이를 통해 let과 const의 등장을 이해해보자.
재선언, 재할당 모두 가능하다.
function greeting() {
var greeting = 'hello';
var greeting = 'bye';
console.log(greeting); // bye
}
greeting();
function greeting() {
var greeting = 'hello';
greeting = 'bye';
console.log(greeting); // bye
}
greeting();
var과 달리 재선언은 불가능하다. 하지만 var과 동일하게 재할당은 가능하다.
흔히 사용하는 변수라고 생각하면 된다.
function greeting() {
let greeting = 'hello';
let greeting = 'bye';
console.log(greeting); // Identifier 'greeting' has already been declared
}
greeting();
function greeting() {
let greeting = 'hello';
greeting = 'bye';
console.log(greeting); // 'bye';
}
greeting();
재선언과 재할당 모두 불가능하다.
function greeting() {
const greeting = 'hello';
greeting = 'bye';
console.log(greeting); // Assignment to constant variable.
}
greeting();
값의 유효범위는 해당 값에 접근할 수 있는 스코프(범위)를 얘기한다.
따라서 정해진 스코프 내에서 어디서든 접근가능하고 외부에서는 접근하지 못함을 의미한다.
function scope를 따른다.
function scope는 값의 유효범위가 함수 스코프임을 뜻한다. 아래와 같이 동일한 함수안에 있다면 특정한 값을 사용할 수 있다.
선언된 함수를 기준으로 모든 하위 함수는 이 스코프에 속한다.
function greeting() {
while (1) {
var greet = 'hello';
break;
}
console.log(greet); // hello
}
greeting();
block scope를 따른다.
block scope는 값의 유효범위가 블록 스코프임을 뜻한다. 동일한 블록({ })안에 있다면 특정한 값을 사용할 수 있다.
아래와 같이 var키워드를 사용할 땐 잘 동작하던 코드가, let을 사용했을 때는 에러가 발생하는 걸 볼 수 있다.
값이 선언된 블록을 기준으로, 모든 하위 블록도 스코프에 속하며 하위블록에서도 접근가능하다. (앞서 설명한 function scope와 동일)
function greeting() {
while (1) {
let greet = 'hello';
break;
}
console.log(greet); // greet is not defined
}
greeting();
값의 선언부와 할당부가 분리되어, 값의 선언부가 코드 내 최상단으로 끌어올려지는 것을 말한다. (이런 특징 때문에 코드 상에서 값이 정의되기 전에 참조할 수 있다)
실제로 동작방식은 인터프리터가 코드를 실행하기 전에, 선언에 대한 메모리 공간을 미리 할당해준다.
중요한 것은 var인 값은 undefined값으로 초기화되며, let과 const인 값들은 메모리 공간만 할당될 뿐 값이 초기화되지 않는다.
무슨 말인지 아래 코드를 보면서 더 이해해보자.
인터프리터가 미리 greet에 대한 메모리 공간을 할당하고, undefined로 값을 초기화했다.
아래 코드처럼 greet 출력 시, 호이스팅 때문에 undefined가 출력된다.
function greeting() {
console.log(greet);
var greet = 'hello';
}
greeting(); // undefined
var과 달리 메모리 할당과 동시에 값이 초기화되지 않는다.
아래 코드처럼 greet를 출력하는 시점에는 변수가 초기화되지 않는 상태이다. 때문에 초기화되지 않는 값에 접근하려는 시도를 했기때문에 에러가 발생하게 된다.
function greeting() {
console.log(greet);
let greet = 'hello';
}
greeting(); // ReferenceError: Cannot access 'greet' before initialization
값을 선언할 때 사용하는 키워드 (var, let, const)들은 설명한 것과 같이
크게 재선언 및 재할당, 스코프(유효범위), 호이스팅 관점에서 비교했다.
글을 작성하면서 var은 모든 관점에서 좀 더 자유로운 키워드인 것 같다고 생각했다. 그래서 개발자마다 var을 사용하는 방식이 다양할 것 같다.
이런 부분이 var로 작성된 코드를 이해하기 어렵게 만드는 것이 아닐까...
또, C++이나 Java와 같은 언어에서의 변수 선언 방식과 다른부분 때문에 그렇게 생각할 수도 있을 것 같다.