JavaScript - Var과 Let의 차이

출처 : Elizeu Dias From Unplash

자바스크립트를 사용할때 변수의 타입으로 var을 사용하곤 했는데, 인텔리제이 Ultimate 버전을 사용할때 IDE에서 var 대신 let을 타입으로 변경할것을 권하는 alert를 자주 보곤 했다. 그 이유를 정리하려고 한다.

Why

우선 let이라는 타입은 ES6(ECMAScript6)에서 추가된 문법이라고 한다. 그럼 왜 ES6에서 새로운 타입이 추가된걸까?

아래 예제 코드를 보자.

JS 코드를 보면, var로 선언된 x가 같은 함수내에서 중복 선언된걸 알 수 있다. 그럼에도 에러없이 마지막에 선언된 xvalueX의 HTML에 입혀져서 출력이되었다.

짧은 코드이기에 이런 코드는 금방 수정할 수 있지만, 만약 수백줄, 수천줄의 코드에서 이런 문제가 있다면 이땐 어떻게 찾아야할까?

중복 선언이 된다면 실제 변수가 호출되는 시점에 따라 다른 값이 사용될수 있으므로 매우 혼란스러울것 같다.

또 한가지가 있다.

브라우저 콘솔창에서 아래와 같이 입력을 했다.

1
2
console.log(name);
var name = "youngjin";
1
2
console.log(age);
let age = 30;

변수를 선언할때 타입을 각각 varlet으로 호출하고, 변수 선언에 앞서 먼저 변수를 호출해서 콘솔에 출력하는 코드이다. 결과는 어떨까?

var로 선언했을 경우는, 변수 name이 선언되기도 전에 호출할 수 있었다. 물론 인터프리터 언어다보니 어떤 값이 있는지는 알수 없었다. 그러나 선언도 하지 않은 변수를 에러없이 undefined로 출력할 수는 있었다.

반면 let으로 선언한 변수 age는 Reference Error가 발생되어 콘솔에 아무것도 출력할수 없었다.

이것만으로 충분히 var을 사용하는 일이 혼란스럽지만 한가지 사례를 더 찾아보았다.

1
2
3
4
console.log(name);
{
var name = "youngjinmo";
}

아예 블럭으로 스코프는 분리한 상태에서 콘솔에 실행해보았다. 결과는 어떨까? varlet으로 변수를 선언했을때를 동시에 실행해보았다.

예측했겠지만, let로 선언했을때는 이번에도 Reference Error가 발생했다.

반면 var로 선언했을때에는 아까보다 한술더떠 다른 스코프의 값을 가져오는데도 성공했다.

이처럼 하위 스코프에서 선언되고 값이 할당된 변수를 끌어올려서 호출할 수 있는 기능을 호이스팅(Hoisting)이라고 한다. 자바 스크립트에서 컨텍스트가 실행되기 때문이라고 하는데, 컨텍스트에 대해서는 나중에 더 정리해볼 예정이다.

더 알아보기

var로 변수를 선언하면 매우 혼란스럽다;; 이런 문제를 해결하기 위해 ES6에서 let이 등장했다.

Benefit

위의 CodePen의 코드에서 중복선언된 x의 타입을 let으로 바꿔보자. 그리고 버튼을 클릭하여 함수를 실행하면, 화면에서 값이 바뀌지 않을것이다.

브라우저 콘솔에서 테스트하면 원인을 알 수 있다.

1
2
3
4
let x = 100;
console.log(x);
let x = 200;
console.log(x);

변수 x의 재정의로 인해 SyntaxError가 발생했다.

결과적으로 let 을 사용하면 변수의 중복선언이 불가능하기 때문에 안전하게 변수를 선언/사용할 수 있다.

varlet의 차이중 또 하나 특징이 있다.

위의 CodePen에서 오른쪽 Result 탭에서 버튼을 클릭해보자. 클릭하기 전 각각 xy가 어떤 값이 할당될지 생각해보고 클릭해보자.

x는 기대했던대로 변화되었지만, y는 아닐것이다. 왜 그런걸까?

main()함수를 살펴보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function main () {
let x = 1;

if (x === 1) {
let x = 2;
let y = 1;

valueX.innerHTML=x;
// expected output: 2
}

valueY.innerHTML=y;
// expected output: 1
}

스코프(scope)를 구분하기 위해 일부러 함수내에서 if문을 작성해서 스코프를 구분했다.

먼저 살펴볼 부분은 변수 x가 중복선언되었다는 점이다. 앞서 let으로 변수를 선언하면 중복선언이 불가능하다고 했다. 그런데 위의 코드는 어떻게 중복선언이 가능했던걸까?

let x가 선언된 스코프의 차이가 이를 설명한다.

가장 먼저 선언된 x는 main 함수를 스코프로 갖는다. 두번째로 선언된 x는 if절을 스코프로 갖는다. 따라서 x는 중복선언된게 아니라 서로 다른 스코프에서 선언된 변수일뿐이다.

따라서 실행화면에서 출력된 x의 값은 1이 아닌 innerHTML가 선언된 스코프의 x값을 가져와서 2가 출력된 것이다.

같은 이유로 y는 값이 출력되지 못했다. y가 선언된 스코프는 if절인데, y의 값을 출력하는 코드인 innerHTML가 선언된 스코프보다 if절이 하위 스코프이기 때문에 y의 값을 가져올수 없었다.

정상적으로 y를 출력하려면 어떻게 해야할까?

if절 안에서 yvar로 선언하는것으로 바꾸고 다시 버튼을 클릭하면 기대했던대로 출력될 것이다.

그러나 이렇게 전역변수를 사용하기 위해 var을 사용하는건 권고되지 않는 방식의 코딩이다. 보다 나은 코드는 변수 ylet으로 선언하되 HTML을 변경하는 innerHTML 코드를 if절 안으로 가져오는 것이다.

정리

let의 사용목적은 아래와 같다.

  • 변수 중복 선언 불가
  • 스코프 규칙 준수

더 알아보기

const

ES6에서는 let뿐만 아니라 const가 추가되었는데, const는 상수를 선언할때 사용한다. 즉 immutable 하게 사용할 변수는 let이 아니라 const로 선언해야 변수의 값을 안전하게 보존할 수 있다.