본문 바로가기
Essays

[Javascript] var를 왜 쓰면 안되나요?

by VincentKim 2023. 4. 8.

짤 출처 : https://imgflip.com/i/59zred

 

시작하기 전에

 오늘은 자바스크립트의 var의 특징들에 대해 알아보고 왜 사용을 지양해야 하는지 그 이유에 대하여 알아보겠습니다.

초기 자바스크립트에서 변수를 선언할 때 var를 사용했었는데요, 다른 프로그래밍 언어에서 동작하는 방식과 많이 달라서 자바스크립트에 입문하는 개발자들을 곤경에 빠트리는 주범이었다고 합니다. 오늘은 왜 var를 사용하면 좋지 않는지 중요한 특성과 var 대신 let과 const를 사용해서 변수를 선언해야 하는 이유에 대해 알아보겠습니다. 

 

1. 변수를 선언하는 키워드가 없어도, 선언과 할당이 가능하다. 

 

something = '👶🏻'; 
console.log(something); // 👶🏻

 

 위 코드는 var를 선언한 것과 동일하게 작동합니다. 뒤에서 언급하겠지만, 'use strict'를 코드 상단에 작성하므로써 strict mode를 사용하면 이런식으로 동작이 가능한 것을 막을 수 있습니다. 

 

'use strict';
something = '👶🏻'; 
console.log(something); //ReferenceError: something is not defined

 

 

2. 중복 선언이 가능하다. 

그렇다면 strict 모드가 var 의 이상한 동작을 모두 막아 줄 수 있을까요? 다음 예제를 봅시다. 

 

'use strict';

var baby = '👶🏻';
var baby = '👶🏻';
console.log(baby);

 

strict mode 임에도 불구하고 var의 이상한 동작은 변함 없습니다. var는 중복 선언이 가능하고 마지막에 선언한 변수로 덮어씌워집니다. 이러한 특징 때문에 실제로 여러 개발자가 함께 작업하는 코드에서 변수의 선언인지 재할당인지 구분하기 어려워 문제를 야기할 수 있습니다. 

 

3. 블럭 레벨 스코프가 되지 않는다. 

일반적으로 대부분의 프로그래밍 언어에서 스코프는 블럭으로 결정됩니다. 스코프는 이름충돌을 방지하고 블럭이 끝났을 때 가비지 컬렉터에 의해 블럭 안의 변수를 청소하게 하여 메모리를 절약하는 역할을 하기 때문에 변수는 블럭 스코프를 활용하여 필요한 곳에서 선언하고 사하는 것이 좋습니다. 그런데 var는 블럭 스코프가 되지 않습니다!  아래 예제를 살펴봅시다. 

 

'use strict'

var cherry = '체리';
{
  var cherry = '🍒';
  {
    var cherry = '🍒🍒';
  }
}
console.log(cherry); //'🍒🍒'

 

 let이나 const를 사용했을 때에는 cherry를 출력하는 위치에서 블럭 스코프에 선언되고 초기화된 '체리'가 출력됩니다. 하지만 var는 블럭을 전부 무시하고 코드 상단으로 hoisting 되어 블럭을 무시하고 마지막 줄에서 선언하고 할당한 값으로 출력된 것을 볼 수 있습니다.

hoisting이란 Javascript 엔진이 코드를 실행하기 전에 변수, 함수, 클래스의 선언문을 최상단으로 해당 스코프에서 끌어올리는 것은 말하는데요, 이를 통해 함수를 선언하기 전에 함수를 출력할 수가 있는 것이지요. 스코프에 대해서는 다음에 더 자세히 살펴봅시다. 

 

let이나 const로 선언된 변수는 해당 스코프 안에서 선언만 hoisting되는 것에 비해 var로 선언한 변수는 그 값까지 global하게 hoisting되어 버립니다. 따라서 블럭 안에서 var로 선언한 변수는 블럭에 상관없이 가장 마지막에 선언한 값으로 할당되어집니다. 

이러한 특성 때문에 이전에는 다른 프로그래밍 랭귀지를 사용하던 개발자가 자바스크립트로 코드를 작성했을 때 일반적인 상식선에서 벗어난 형태로 작동되기 때문에 애를 먹는 경우가 많았다고 합니다. 한마디로 선 넘는거죠. 

 

4. 근데 함수 레벨 스코프는 지원합니다. 

function example() {
  var meow = '🐈';
}
console.log(dog); // Error: meow is not defined

 

블럭 스코프는 지원하지 않으면서 함수 스코프는 지원합니다. 그나마 다행이라고 해야할까요? 

 

5. One more thing

 

function loop() {
  const array = [];
  // var i;
  for (var i = 0; i < 5; i++) {
    array.push(function () {
      console.log(i);
    });
  }
  return array;
}

const array = loop();
array.forEach((func) => func()); // 5 5 5 5 5

 

위 코드는 주석처리한 부분에서 var i; 로 선언한것과 동일하게 작동합니다. for문 안에서 let을 사용했다면 1 2 3 4 5가 순차적으로 출력되었겠지만 5가 출력되는 것을 볼 수 있는데요, 이같은 일이 발생하는 이유는 var가 for문의 블럭을 무시하고 함수 스코프는 지원하므로 loop() 의 스코프에서 hoisting 되어 최종적으로 변경된 i의 정보를 출력하게 되는 것입니다. 

 

 

 

 

오늘은 var의 이상한 특징들에 대해 살펴봤습니다. 다행히 ES6에서 let과 const가 추가되어 이러한 돌발행동으로부터 자유로워졌으니 var를 사용하지 말고 let과 const를 사용합시다!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

댓글