Logo

[ES2015] let으로 변수 선언하기 1

본 포스팅에서는 ES2015를 통해 자바스크립트에 추가된 let 키워드에 대해서 알아보도록 하겠습니다.

문제의 코드

먼저 다음 예제 코드를 살펴보시죠.

function findUser(id) {
  if (id > 0) {
    var successMsg = "사용자를 조회하였습니다.";
    console.log(successMsg);
    console.log({ id: id, name: "사용자 #" + id });
  } else {
    var failureMsg = "잘못된 아이디입니다!";
    console.log(failureMsg);
  }
  console.log("실패 메시지:", failureMsg);
}

findUser 함수는 사용자 아이디가 0보다 크면 성공 메시지를 출력하고 아니면 실패 메시지를 출력합니다. 그리고 if-else 문을 빠져나온 후, 실패 메시지를 다시 한 번 출력하고 있습니다.

자, 그럼 다음과 같이 1을 인자로 이 함수를 호출하면 마지막에 출력하는 실패 메시지는 뭐라고 출력이 될까요?

findUser(1);

다음과 같이 오류가 발생하지 않고 undefined가 출력이 됩니다!

사용자를 조회하였습니다.
{ id: 1, name: '사용자 #1' }
실패 메시지: undefined

첫 개발 언어가 자바스크립트인 분들은 이 결과가 당연하게 느낄 수도 있겠지만, 저처럼 다른 언어에서 넘어온 개발자들은 당황스럽게 느껴질 수 있는 결과입니다.

else 블록은 실행되지 않았기 때문에, failureMsg 변수는 선언된 적도 없는데 어떻게 이런 결과가 나오는 것일까요?

또한 설사 어떤 연유로 else 블록이 실행되었다고 쳐도, 어떻게 else 블록 외부에서 else 블록 내부에서 선언되었던 failureMsg에 접근이 가능할까요?

var의 Function Scope과 Variable Hosting

정답은 자바스크립트의 var 키워드에서 찾을 수 있습니다. 이전 포스팅에서 설명드렸던 것 처럼, var로 선언된 변수는 Function 범위에서 Hosting이 됩니다.

따라서 위 코드는 자바스크립트 엔진에 의해서 다음과 같이 해석이 됩니다.

function findUser(id) {
  var successMsg; // hosting
  var failureMsg; // hosting

  if (id > 0) {
    successMsg = "사용자를 조회하였습니다.";
    console.log(successMsg);
    console.log({ id: id, name: "사용자 #" + id });
  } else {
    failureMsg = "잘못된 아이디입니다!";
    console.log(failureMsg);
  }
  console.log("실패 메시지:", failureMsg);
}

왜 결과가 그렇게 나왔는지 위 코드가 모든 것을 설명해주는데요.

successMsg 변수와 failureMsg 변수가 findUser 함수의 최상단으로 hoisting 되기 때문에, if-else 내부, 외부 가리지 않고 접근이 가능합니다. 기 선언된 변수에 접근하는 것이므로 오류를 일으킬 이유도 없고요.

var 대신 let 사용하기

위 문제를 해결할 수 있는 가장 간단한 방법은 변수를 선언할 때, let 대신에 var를 사용하는 것입니다.

function findUser(id) {
  if (id > 0) {
    let successMsg = "사용자를 조회하였습니다.";
    console.log(successMsg);
    console.log({ id: id, name: "사용자 #" + id });
  } else {
    let failureMsg = "잘못된 아이디입니다!";
    console.log(failureMsg);
  }
  console.log("실패 메시지:", failureMsg);
}

let으로 선언된 변수는 함수가 아닌 ifelse문 같은 블록 단위로 Scoping이 됩니다. 그리고 var처럼 변수 Hosting을 일으키기 않습니다. 따라서 위 코드를 실행시키면 예상대로 오류를 발생시킵니다.

console.log('실패 메시지:', failureMsg)
                       ^
ReferenceError: failureMsg is not defined

let 사용 시 주의 사항

let으로 선언된 변수는 다시 선언될 수가 없습니다. 즉 다음과 같은 코드를 실행하면 오류가 발생합니다.

let failureMsg = '잘못된 아이디입니다!'
let failureMsg = 'Wrong ID!'
let failureMsg = 'Wrong ID!'
                 ^^^^^^^^^^^
SyntaxError: Identifier 'failureMsg' has already been declared

var는 어차피 변수를 hosting 해버리기 때문에 여러 번 선언하는 게 큰 의미가 없겠지만, hosting을 하지 않는 let 경우에는 좀 더 엄격하게 변수 선언을 해주셔야 합니다.

마치면서…

이상으로 let 사용하여 좀 더 안정적으로 변수 선언을 하는 방법을 살펴보았습니다. let을 사용하면 좀 더 예측가능한 코드를 작성할 수 있기 때문에 var보다는 가급적 let을 사용하시는 게 어떨까요? (물론 코드를 돌릴 자바스크립트 엔진에 ES2015를 지원한다면…)

참고

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let