var 대신 let과 const를 사용하는 이유

open_h·2020년 11월 19일
1

JavaScript

목록 보기
1/5
post-thumbnail

​ 자바스크립트에서 변수를 선언할 때 var 키워드 대신 ES6의 let , const 키워드를 사용하는 것이 더 바람직하다고 배운다. 왜 그래야 하는걸까? 그저 재할당을 막아주는 const 의 기능적 특징 때문에 사용하는 걸까?

var 키워드의 문제점

​ 다른 언어와 비교했을 때, 자바스크립트에서 var 로 선언된 변수는 개발자가 특별히 주의를 기울이지 않으면 발생할 수 있는 문제들이 있다. 대부분의 문제는 전역 변수로 인해 발생한다. 불필요하거나 지나친 전역 변수는 넓은 스코프로 인해 변수가 어디에서 어떻게 사용될지 파악하기 어렵고 변수의 스코프를 축소시키는데 방해되는 등 namespace pollution의 원인이 된다.

  1. 개발자의 실수를 유발하는 var

    var 키워드는 생략이 가능하며 이는 개발자에게 자유를 주는 것이다. 자유롭다는 장점(장점이 아닐 수도 있다. 언어 문법의 특징이라고 보는 게 더 정확하다)이 있지만 전역 변수를 만들 가능성이 높아진다.

    또한 변수의 중복 선언이 가능하다. 이 또한 개발자에게 자유를 주어 생기는 문제이다. 의도하지 않게 변수값의 변경이 일어날 가능성이 크다.

   // 키워드 생략 가능
   num = 1;
   
   // 변수의 중복 선언 가능
   var favorite = "dog"; 
   var favorite = "cat"; // 중복 선언 허용. 
   // 코드가 복잡해졌을 때 이미 favorite이라는 변수를 사용한 사실을 개발자가 잊는다면...?
  1. 선언되지 않은 변수에 대한 참조

    var 키워드의 경우 let 과 달리 위 코드 처럼 변수를 선언하기 이전에 참조가 가능해지는 문제가 발생한다. 이 문제를 제대로 논하기 위해서는 hoisting호이스팅에 대해 알아보아야 한다.

   console.log(a); // undefined. 즉 a는 이미 선언된 상태이다.
   var a;
   console.log(b); // ReferenceError: b is not defined
   let b;
  1. Function Level Scope 함수 레벨 스코프

    Function Level Scope함수 레벨 스코프에서는 함수 내에서 선언된 변수는 함수 내에서만(함수 코드 블럭 {} 내에서만) 유효하기에 외부에서 참조할 수 없다.

    Block Level Scope블록 레벨 스코프는 모든 코드 블록(함수를 포함하여 if , for , while 등) 내에서 선언된 변수가 해당 코드 블록 내에서 유효한 것이다.

    var 키워드로 생성한 변수는 함수 레벨 스코프 전역 함수 외부에서 생성한 변수는 전부 전역 변수가 되어 1번 문제와 마찬가지로 전역 변수를 남발할 가능성이 높다. 예를 들어 for 문에서 선언한 변수를 for 문 외부에서 참조할 수 있게 된다. 아래 코드를 확인해보자.

   var myList = [];
   for(var i=0; i<5; i++){
     myList.push(i);
   }
   console.log(i); // 5

개발자는 변수 ifor 문의 외부에서 참조하고 싶지 않을 수가 있다. 그러나 var 는 앞서 말했듯이 함수 레벨 스코프이기 때문에 i 가 전역변수가 될 수 있는 것이다. 하지만 아래와 같은 경우가 더 무서울지도 모른다.

var myList = [];
for(var i=0; i<5; i++){
  myList.push(function(){
    console.log(i);
  })
}

myList[0](); //5
myList[3](); //5

위 코드에서 myList 의 요소들은 함수이다. for 문에서는 언뜻 보기에 0, 1, 2, 3, 4를 출력하는 함수를 myList 에 넣어주는 것처럼 보일 수 있다. 하지만 for 문이 끝나고 i 값이 5이기에 함수 내부의 console.log(i) 라는 코드는 5를 출력하게 된다. 즉, myList 내부의 모든 함수는 동일한 함수가 된다. 이와 같이 자바스크립트에서 함수 레벨 스코프로 인해 발생하는 문제를 해결하기 위해 closure클로저를 활용할 수 있다. 하지만 let 키워드를 이용하면 굳이 복잡하게 클로저를 사용하지 않아도 된다.

ES6 letconst

​ ES6에서 자바스크립트 새로운 문법과 기술이 등장하면서 변수를 선언하는 키워드인 letconst 는 위와 같은 var 에 대한 문제를 보완하기 도입되었다.

let 키워드

var 은 함수 레벨 스코프였던 반면, let 은 블록 레벨 스코프 변수를 선언한다. 또한 let 으로 변수 이름을 중복하여 선언할 수 없으며 SyntaxError문법 에러가 발생한다.

let a = 10;
let c = 2;
//아래 코드 블럭은 함수 코드 블럭이 아닌 것을 주목하자.
{
 let a = 20;
 let b = 5;
}
let c = 50; // // Uncaught SyntaxError: Identifier 'bar' has already been declared
console.log(a); // 10
console.log(b); // ReferenceError: b is not defined

​ 아래 코드에서 let 키워드는 var 과 다르게 변수 선언시 호이스팅이 일어나지 않는다. 여기서 호이스팅에 대해 이해하고 변수가 어떻게 생성되는지 등 코드 독해에 대해 더 자세히 설명하려면 Execution Context실행 컨택스트라는 자바스크립트의 핵심 원리를 이해해야 한다. 여기서는 let 으로 생성된 변수는 아래 코드와 같이 변수 호이스팅이 일어나지 않는다고만 짚고 넘어간다.

console.log(a); // undefined (호이스팅이 일어남)
var a;

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

Global Object전역 객체

​ 전역 객체란 모든 객체의 최상위 객체로 브라우저에서 window 객체가 그 예시이다. var 키워드로 선언된 변수는 전역 객체의 프로퍼티가 된다. 그러나 let 으로 선언한 전역 변수는 전역 객체의 프로퍼티가 될 수 없다.

var a = 10;
let b = 5;
console.log(window.a) // 10
console.log(window.b) // undefined

const 키워드

​ constant(상수)의 약자로 말 그대로 불변의 값을 가지는 변수 선언을 위해 사용되는 키워드이다(그러나 꼭 상수를 위해 사용하는 것은 아니다). letconst 는 블록 레벨 스코프를 갖는 등 대부분 동일한 특징을 가지고 있다. 따라서 const 키워드가 let 과 다른점만 살펴보자.

const 키워드로 선언된 변수는 반드시 선언과 동시에 할당이 이루어져야 하며 let 과 달리 재할당이 금지된다. 이러한 특징 때문에 불변의 값에 대해서는 const 를 사용하는 것은 코드의 가독성을 높이고 유지보수에 도움이 되기에 적절한 고정값에 대해서 적극적으로 사용하는 것이 바람직하다. 재할당이 필요없는 변수를 let 으로 선언한다면 개발자가 실수로 그 값을 변경할 가능성이 있기에 재할당이 필요없는 변수는 모두 const 로 선언하는 것이 좋다.

const a; // SyntaxError: Missing initializer in const declaration
const b = 10;
b = 20; // TypeError: Assignment to constant variable.
const member = ["a", "b", "c", "d"];
// 의미를 파악하기 어렵다. 가독성이 떨어짐.
for(let i=0; i<4; i++) { /* code... */ }
for(let i=0; i<member.length; i++) { /* code... */ }

// const의 바람직한 활용.
const MEMBER_NUM = member.length;
for(let i=0; i<MEMBER_NUM; i++) { /* code... */ }

객체와 const

const 로 선언된 객체에 다른 객체 자체를 다시 할당할 수 없는 것은 쉽게 납득이 된다. 하지만 주의해야 할 것이 const 로 선언된 객체라 하더라도 객체의 프로퍼티에 접근(프로퍼티 추가, 삭제 혹은 프로퍼티 값의 변경)은 할 수 있다는 점이다. 왜 이렇게 되는지 이해하기 위해서는 자바스크립트에서 primitive type기본형 타입과 reference type참조형 타입 변수가 메모리가 할당될 때 어떻게 다른지 자바스크립트의 메모리 관리에 대해 더 알아보아야 한다.

const myObj = { a: 10 }
myObj = { a: 10 } // TypeError: Assignment to constant variable.
myObj = { b: 5, k: 20}  // TypeError: Assignment to constant variable.

// const로 선언된 객체라 하더라도 프로퍼티에 접근은 가능
myObj.newKey = 10;
myObj.a = 5;
console.log(myObj); // { a: 5, newKey: 10 }

결론

​ ES6를 사용한다면 변수 선언은 재할당이 필요한 경우에만 스코프를 최대한 좁게 하여 let , 나머지는 안전하게 재할당이 불가능한 const 를 사용한다. 객체를 재할당 하는 경우는 드문 편이기에 재할당을 방지하기 위해 객체도 const 로 선언해주는 것이 좋다.

한줄요약

변수를 선언할 때 잘 모르겠으면 일단 변수를 const 로 선언하고 나중에 재할당이 필요하면 때 let 으로 바꾸는 것이 안전하다!


혹시 잘못된 내용이 있거나 부족한 부분이 있다면 말씀 부탁드립니다. 지적은 진심으로 감사히 받겠습니다!

profile
The only thing that interferes with my learning is my education.

0개의 댓글