본문 바로가기
개발(Development)/JS(자바스크립트)

[자바스크립트] 변수 선언 방식 차이: var / let / const

by 카레유 2020. 10. 14.

자바스크립트의 변수 선언은 var로만 가능했으나,

ES6(ES2015)부터 let과 const가 추가 되었다.

 

옛날의 var가 최신의 let(변수), const(상수)로 분리되었다고 생각할 수 있으나, 내부 사정은 상당히 다르다.

(참고로 여전히 var도 함께 사용이 가능하다)

 

var와 let, const가 어떻게 다른지 상세하게 정리해본다.

 

 

# var, let, const 차이점 5가지

1. 중복선언 가능 여부

2. 재할당 가능 여부

3. 변수 스코프 유효범위

4. 변수 호이스팅 방식

5. 전역객체 프로퍼티 여부

 

 

 

#1. 중복선언

1. var : 중복 선언이 가능하다.

// 첫번째 변수 선언+초기화
var a = 10;
console.log(a); // 10


// 두번째 변수 선언+초기화
var a = 20;
console.log(a); // 20


// 세번째 변수 선언(초기화X)
var a;
console.log(a); // 20

 

var로 선언한 변수는 중복해서 선언(+초기화)가 가능하다.

이 경우, 마지막에 할당된 값이 변수에 저장된다.

 

단, 초기화 없이 선언만 한 경우엔 선언문 자체가 무시된다.(에러는 발생하지 않음)

 

기존에 선언해둔 변수의 존재를 까먹고, 값을 재할당하게 되는 등의 실수가 발생하기 쉽다.

Java나 Python 같은 언어에 익숙한 경우, 이게 뭔가 싶을 수 있다.

 

 

 

2. const, let : 중복 선언 불가능

// let 중복 선언
let a = 10;
let a = 20; // SyntaxError: Identifier 'a' has already been declared

// const 중복 선언
const b = 10;
const b = 20; // SyntaxError: Identifier 'b' has already been declared

 

let, const로 선언한 변수는 중복 선언이 불가능하다.

코드에서 보는 것처럼 이미 선언한 변수를 다시 선언할 경우, 에러가 발생한다.

var에 비해서 코드의 안정성을 높여줄 수 있는 방식으로, 다른 언어를 쓰던 사람들게도 익숙할 것이다.

 

 

 

#2. 재할당

1. var, let : 값의 재할당이 '가능'한 변수다.

var a = 10;
a = 20;
console.log(a);  // 20


let b = 111;
b = 222;
console.log(b);  // 222

 

var와 let은 변수를 선언하는 키워드다.

변수 선언 및 초기화 이후에 반복해서 다른 값을 재할당 할 수 있다.

 

 

 

2. const : 값의 재할당이 '불가능'한 상수다.

const c = 111;
c = 222;  // TypeError: Assignment to constant variable.

 

const는 상수를 선언하는 키워드다.

처음에 선언 및 초기화하고 나면 다른 값을 재할당 할 수 없다.

 

(참고) const는 처음 선언할 때 반드시 초기화(값 할당)를 해주어야 한다.

const a = 10;

const b;  // SyntaxError: Missing initializer in const declaration

 

 

 

#3. 스코프(Scope)

스코프란 유효한 참조 범위를 말한다.

예를 들어, 함수 내부에서 선언된 변수는 함수 내부에서만 참조가 가능하다.

이 경우 변수의 스코프는 함수 내부로 한정 된다.

 

자바스크립트는 var로 선언한 변수의 스코프와 let, const로 선언한 변수의 스코프가 다르다.

 

 

1. var : 함수 레벨 스코프(function-level scope)

var는 함수 내부에 선언된 변수만 지역변수로 한정하며, 나머지는 모두 전역변수로 간주한다.

function hello(){
    var a = 10;
    console.log(a);
}

hello(); // 10

console.log(a);  //ReferenceError: a is not defined

 

hello 함수 내부에서 선언된 a변수는 함수 내부에서만 참조가 가능하며, 외부에서 참조시 에러가 발생한다.

 

하지만, 함수를 제외한 영역에서 var로 선언한 변수는 '전역변수'로 취급된다.

if(true) {
    var a = 10;
    console.log(a); // 10
}


console.log(a);  // 10

 

Java, Python 등에 익숙한 사람에겐 이게 뭔가 싶을만한 코드다.

 

자바스크립트애서는

if문, for문, while문, try/catch 문 등의 코드 블럭{ ... } 내부에서 var로 선언된 변수를 전역 변수로 간주한다.

그래서 블럭 외부에서도 어디에서나 참조할 수 있다.

 

그러나, let과 const는 다르다.

 

 

2. let, cost : 블록 레벨 스코프(block-level scope)

let, const는 함수 내부는 물론, if문이나 for문 등의 코드 블럭{ ... } 에서 선언된 변수도 지역변수로 취급한다.

if(true) {
    let a = 10;
    console.log(a); // 10
}

console.log(a);  // ReferenceError: a is not defined

 

if문의 블럭 내부에서 let으로 선언된 변수는 외부에서 참조되지 않음을 알 수 있다.

 

 

당연히 함수 내부에서 선언된 변수도 외부에서 참조할 수 없다.

function hello() {
    let a = 10;
    console.log(a); // 10
}

console.log(a);  // ReferenceError: a is not defined

 

정리하자면,

var는 함수 내부에 선언된 변수만 지역 변수로 인정하는 함수 레벨 스코프이다.

let, const는 블록 내부에서 선언된 변수까지도 지역변수로 인정하는 블록 레벨 스코프이다.

* 참고로 블록은 if문이나 for문 등에서 중괄호{ } 로 둘러싸인 코드 영역을 말한다.

 

 

 

#4. 호이스팅

자바스클립트는 코드를 실행하기 전, 일종의 '코드 평가 과정'을 거치는데,

이 때 '변수 선언문'을 미리 실행두기 때문에 뒤에서 선언된 변수도 앞의 코드에서 참조할 수 있게 된다.

이를 변수 호이스팅이라고 한다.

 

* 코드 평가 과정에 대해서는 아래 글 참고

[자바스크립트] 코드 실행 2단계와 변수/함수 생성 과정

 

var와 let/const 는 호이스팅 과정도 다르다.

 

 

1. var: 변수 호이스팅이 발생한다.

console.log(a);  // undefined

var a = 10;

console.log(a);  // 10

 

뒤에서 선언된 변수 a가 앞에서 참조되었음에도 에러를 발생시키지 않는다.

코드 실행 전에 자바스크립트 엔진이 미리 1) 변수를 선언하고,  2)undefined로 초기화해 두었기 때문이다.

이게 바로 var로 선언된 변수의 호이스팅이다.

 

 

2. let, const: 변수 호이스팅이 발생한다. 하지만 다른 방식으로 작동한다.

console.log(a);  // ReferenceError: Cannot access 'a' before initialization

let a = 10;

 

뒤에서 선언된 변수를 앞에서 참조하려 하니 에러가 발생한다.

마치 호이스팅이 발생하지 않는 것처럼 보인다.

 

이런 현상이 발생하는 이유는 let, const의 호이스팅 과정이 var와 다르게 진행되기 때문이다.

 

let/const로 변수를 선언하는 경우,

코드 실행 전에는 1) 변수 선언만 해두며, 2) 초기화는 코드 실행 과정에서 변수 선언문을 만났을 때 수행한다.

 

그래서 호이스팅이 발생하기는 하지만, 값을 참조할 수 없어서 호이스팅이 발생하지 않는 것처럼 보이는 것이다.

변수의 선언과 초기화 사이에 일시적으로 변수 값을 참조할 수 없는 구간을 TDZ(Temporal Dead Zone)라고 한다.

 

그렇다면, 호이스팅이 발생하는걸 어떻게 확인할 수 있을까?

 

아래의 두 코드를 비교해보면 알 수 있다.

let a = 10;  // 전역변수 a선언

if(true){
    console.log(a); // 10
}

 

이 코드는 전역변수로 선언된 a의 값 10을 if문 블럭에서 참조하여 출력하고 있디.

 

 

let a = 10;  // 전역변수 a선언

if(true){
    console.log(a);  // ReferenceError: Cannot access 'a' before initialization
    let a = 20;  // 지역변수 a 선언
}

 

이 코드는 if문 블럭 내부에서 지역변수 a를 다시 선언했다.

이 경우, 지역변수 a 앞에서 console.log()로 참조시 에러가 발생한다.(전역 변수 a가 있음에도!!!)

 

왜냐하면 지역변수 a가 호이스팅되면서 TDZ 구간이 만들어졌기 때문이다.

즉, let으로 선언된 변수도 호이스팅이 발생함을 알 수 있다.

(참고로 지역변수가 전역변수보다 우선 순위를 갖는다)

 

 

 

#5. 전역객체 프로퍼티 여부

1. var : var로 선언된 변수는 전역객체(브라우저 환경의 경우 window)의 프로퍼티다.

var a = 10;

console.log(window.a);  // 10
console.log(a);  // 10

 

브라우저 환경(크롬 콘솔 등)에서 위 코드 실행 시,

var로 선언한 변수 a는 브라우저 전역객체인 window의 프로퍼티로 할당된다.

 

 

2. let, const : let/const 로 선언된 변수는 전역객체 프로퍼티가 아니다.

let a = 10;

console.log(window.a);  // undefined
console.log(a);  // 10

 

브라우저 환경(크롬 콘솔 등)에서 위 코드 실행 시,

let이나 const로 선언한 변수 a는 브라우저 전역객체인 window의 프로퍼티로 할당되지 않았음을 알 수 있다.

(window.a = undefined)

 


# 결론(제안)

1순위: const를 최우선적으로 사용한다.

2순위: let은 변수 값을 재할당할 필요가 있을 때만 사용한다.

3순위: var는 ES6 이후 부터... 특별한 경우를 제외하곤 쓸 필요가 없어 보인다.

 

 

코딩 스타일은 다들 다르겠지만,

개인적으로는 const와 let만 사용하는 편이며, var는 테스트 할때 외에는 거의 사용하지 않는다.

 

참고로 구글의 자바스크립트 스타일 가이드 다음과 같은 문장이 있다.

Use const and let

Declare all local variables with either const or let.

Use const by default, unless a variable needs to be reassigned.

The var keyword must not be used.

 

1. const와 let을 이용해서 변수를 선언라.

2. 값을 재할당하는 경우가 아니라면, const를 디폴트로 사용하라.

3. var 절대로 사용하지 말라

 

출처 : https://google.github.io/styleguide/jsguide.html#features-use-const-and-let  

 

 

자바스크립트의 변수가 메모리에 어떻게 저장되고 참조되는지는 다음 글 참고.

[자바스크립트] 메모리 구조, 원시타입 변수 생성 원리, 가비지컬렉터

 

 

댓글