[JS] var, let, const 알고 사용하자!

go·2021년 9월 6일
1

JavaScript

목록 보기
3/4
post-thumbnail

코딩 테스트 준비를 하면서 변수 선언할 때 사용되는 var, let, const의 차이점에 대해 정확하게 인지하지 못하고 있었습니다. 찝찝한 마음으로 공부를 하다가 확실하게 알게 사용하고 싶어 공부한 내용을 포스팅하려고 합니다.

ES6는 이러한 var 키워드의 단점을 보완하기 위해 let과 const 키워드를 도입하였습니다.

블록 레벨 스코프

대부분의 프로그래밍 언어는 블록 레벨 스코프를 따르지만 자바스크립트는 함수 레벨 스코프를 따릅니다.

  • 함수 레벨 스코프 : 함수 내에서 선언된 변수는 함수 내에서만 유효하며 함수 외부에서는 참조할 수 없습니다. 즉, 함수 내부에서 선언한 변수는 지역 변수이며 함수 외부에서 선언한 변수는 모두 전역 변수입니다.
  • 블록 레벨 스코프 : 모든 코드 블록 내에서 선언된 변수는 코드 블록 내에서만 유효하며 코드 블록 외부에서는 참조할 수 없습니다. 즉, 코드 블록 내부에서 선언한 변수는 지역 변수입니다.
var foo = 123; // 전역 변수

console.log(foo); // 123

{
  var foo = 456; // 전역 변수
}

console.log(foo); // 456

블록 레벨 스코프를 따르지 않는 var 키워드의 특성 상, 코드 블록 내의 변수 foo는 전역변수입니다. 그런데 이미 전역 변수 foo가 선언되어 있습니다. var 키워드를 사용하여 선언한 변수는 중복 선언이 허용되므로 위의 코드는 문법적으로 아무런 문제가 없지만, 코드 블록 내의 변수 foo는 전역 변수이기 때문에 전역에서 선언된 전역 변수 foo의 값 123을 새로운 값 456으로 재할당하여 덮어쓰게 됩니다.

ES6는 블록 레벨 스코프를 따르는 변수를 선언하기 위해 let 키워드를 제공합니다.

let foo = 123; // 전역 변수

{
  let foo = 456; // 지역 변수
  let bar = 456; // 지역 변수
}

console.log(foo); // 123
console.log(bar); // ReferenceError: bar is not defined

let 키워드로 선언된 변수는 블록 레벨 스코프를 따릅니다. 위 코드에서 코드 블록 내에 선언된 변수 foo는 블록 레벨 스코프를 갖는 지역 변수입니다. 전역에서 선언된 변수 foo와는 다른 별개의 변수입니다. 또한, 변수 bar도 블록 레벨 스코프를 갖는 지역변수이므로 전역에서는 변수 bar를 참조할 수 없습니다.

클로저

블록 레벨 스코프를 지원하는 let 은 var 보다 직관적입니다.

var funcs = [];

// 함수의 배열을 생성하는 for 루프의 i는 전역 변수다.
for (var i = 0; i < 3; i++) {
  funcs.push(function () { console.log(i); });
}

// 배열에서 함수를 꺼내어 호출한다.
for (var j = 0; j < 3; j++) {
  funcs[j]();
}

자바스크립트의 함수 레벨 스코프로 인하여 for 루프의 초기화 식에 사용된 변수가 전역 스코프를 갖게 되어 발생하는 문제를 회피하기 위해 클로저를 활용한 방법이다.

변수 중복 선언 금지

var 키워드로 동일한 이름을 갖는 변수를 중복해서 선언할 수 있지만,

let, const 키워드로는 동일한 이름을 갖는 변수를 중복 선언할 수 없습니다. 변수를 중복 선언하면 문법 에러가 발생합니다.

var foo = 123;
var foo = 456;  // 중복 선언 허용

let bar = 123;
let bar = 456;  // Uncaught SyntaxError: Identifier 'bar' has already been declared

호이스팅(Hoisting)

자바스크립트는 ES6에서 도입된 let, const를 포함하여 모든 선언(var, let, const, function, function*, class)을 호이스팅합니다. 호이스팅이란, var 선언문이나 function 선언문 등을 해당 스코프의 선두로 옮긴 것처럼 동작하는 특성을 말합니다.

하지만 var 키워드로 선언된 변수와는 달리 let 키워드로 선언된 변수를 선언문 이전에 참조하면 참조 에러가 발생합니다. 이는 let 키워드로 선언된 변수는 스코프의 시작에서 변수의 선언까지 일시적 사각지대에 빠지기 때문입니다.

console.log(foo); // undefined
var foo;

console.log(bar); // Error: Uncaught ReferenceError: bar is not defined
let bar;

선언과 초기화

let은 재할당이 자유로우나 const는 재할당이 금지됩니다.

주의할 점은 const는 반드시 선언과 동시에 할당이 이루어져야 한다는 것입니다. 그렇지 않으면 문법 에러가 발생합니다.

const FOO = 123;
FOO = 456; // TypeError: Assignment to constant variable.

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

상수

상수는 가독성과 유지보수의 편의를 위해 적극적으로 사용해야 합니다.

// 10의 의미를 알기 어렵기 때문에 가독성이 좋지 않다.
if (rows > 10) {
}

// 값의 의미를 명확히 기술하여 가독성이 향상되었다.
const MAXROWS = 10;
if (rows > MAXROWS) {
}

const와 객체

const는 재할당이 금지됩니다. 이는 const 변수의 타입이 객체인 경우, 객체에 대한 참조를 변경하지 못한다는 것을 의미합니다. 하지만 이때 객체의 프로퍼티는 보호되지 않습니다. 즉, 재할당은 불가능하지만 할당된 객체의 내용(프로퍼티의 추가, 삭제, 프로퍼티 값의 변경)은 변경할 수 있습니다.

const user = { name: 'Lee' };

// const 변수는 재할당이 금지된다.
// user = {}; // TypeError: Assignment to constant variable.

// 객체의 내용은 변경할 수 있다.
user.name = 'Kim';

console.log(user); // { name: 'Kim' }

정리

변수 선언에는 기본적으로 const를 사용하고 let은 재할당이 필요한 경우에 한정해 사용하는 것이 좋습니다. 원시 값의 경우, 가급적 상수를 사용하도록 하고, 객체를 재할당하는 경우는 생각보다 흔하지 않기 때문에 const 키워드는 의도치 않은 재할당을 방지해주기 때문에 보다 안전하게 사용할 수 있습니다.

  • ES6를 사용한다면 var 키워드는 추천하지 않습니다.
  • 재할당이 필요한 경우에 한정해 let 키워드를 사용합니다. 이때 변수의 스코프는 최대한 좁게 만듭니다.
  • 변경이 발생하지 않는(재할당이 필요 없는 상수) 원시 값과 객체에는 const 키워드를 사용합니다. const 키워드는 재할당을 금지하므로 var, let 보다 안전합니다.

변수를 선언하는 시점에는 재할당이 필요할지 잘 모르는 경우가 많고, 객체는 의외로 재할당을 하는 경우가 드물기 때문에 변수를 선언할 때에는 일단 const 키워드를 사용하도록 하자! 반드시 재할당이 필요하다면(반드시 재할당이 필요한지 한번 생각해 보고) 그때 constlet 키워드로 변경해도 결코 늦지 않습니다.

var

  • 중복 변수 허용 가능
  • 어디든 선언이 가능하고, 변수 값 할당도 어디서든 가능함

let

  • 중복 변수 허용 불가능
  • 블록 안에서만 유효. 블록 외부에서 참조 불가능 (블록 레벨 스코프)

const

  • 상수(변하지 않는 값)를 위해 사용
  • 중복 변수 허용 불가능
  • 블록 안에서만 유효. 블록 외부에서 참조 불가능 (블록 레벨 스코프)
  • 변수 선언과 값 할당이 동시에 이루어져야 함 (재할당 금지)
  • 지정된 값은 수정할 수 없음
  • 원시값이 들어가는 변수에 사용 적합

본 글은 [poiemaweb]을 참고하여 작성되었음을 밝힙니다.

0개의 댓글