Original article: Var, Let, and Const – What's the Difference?

ES2015(ES6)에서 반짝이는 새로운 기능들이 많이 등장했습니다. 2020년이 된 지금, 많은 JavaScript 개발자들이 그 기능들을 사용하기 시작했을 것이며 또 익숙해졌을텐데요. 여전히 그 중 몇몇은 일부 개발자들에게 미스터리로 남아있을 수 있습니다.


ES6에 포함된 기능 중 하나는 변수 선언에 사용할 수 있는 letconst의 추가입니다. 지금껏 애용해온 var와 다른 점은 무엇일까요? 이 글은 여전히 명확히 이해하지 못 한 당신을 위한 것입니다.

Var

ES6의 등장 이전에는 문제점들이 있음에도 불구하고 var로 변수를 선언하는 것이 지배적이었는데요. 따라서 새로운 변수 선언 방식이 등장할 수밖에 없었습니다. 우선, 문제점에 대해 논의하기 전에 var 자체에 대해 더 이해해봅시다.

Scope of var

범위는 기본적으로 변수를 사용할 수 있는 위치를 의미합니다. var 선언은 전역 범위 혹은 함수 범위로 지정됩니다.


var변수가 함수 외부에서 선언될 때의 범위는 전역입니다. 즉, 함수 블록 외부에서 var를 사용하여 선언된 모든 변수를 전체 윈도우 상에서 사용할 수 있는 것이죠.


var가 함수 내에서 선언될 때는 함수 범위로 지정됩니다. 즉, 해당 함수 내에서만 사용하고 접근할 수 있습니다.


자세한 이해를 돕기위해 아래의 예제를 살펴봅시다.

    var greeter = "hey hi";
    
    function newFunction() {
        var hello = "hello";
    }

여기서 hello가 함수 범위인 반면에, greeter는 함수 밖에 존재하므로 전역 범위를 가지게 됩니다.

    var tester = "hey hi";
    
    function newFunction() {
        var hello = "hello";
    }
    console.log(hello); // error: hello is not defined

hellonewFunction() 함수 밖에서 사용할 수 없기 때문에 에러가 발생하게 됩니다.

var 변수는 재선언되고, 업데이트될 수 있습니다.

같은 범위 내에서라면 아래의 두 경우와 같이 수정이 가능하며 에러가 발생하지 않습니다.

    var greeter = "hey hi";
    var greeter = "say Hello instead";
    var greeter = "hey hi";
    greeter = "say Hello instead";

var의 호이스팅

호이스팅이란 변수와 함수 선언이 맨 위로 이동되는 자바스크립트 매커니즘인데요. 아래와 같이 코드를 짜면:

    console.log (greeter);
    var greeter = "say hello"

자바스크립트는 다음과 같이 해석하기 때문에:

    var greeter;
    console.log(greeter); // greeter is undefined
    greeter = "say hello"

var변수는 범위 내에서 맨 위로 올려지고, 값은 undefined(정의되지 않음)으로 초기화됩니다.

var의 문제점

아래의 예제를 토대로 var를 사용할 시 따라오는 취약점에 대해 이야기해보겠습니다.

    var greeter = "hey hi";
    var times = 4;

    if (times > 3) {
        var greeter = "say Hello instead"; 
    }
    
    console.log(greeter) // "say Hello instead"

time > 3true를 반환하기 때문에 greeter"say Hello instead"로 재정의됩니다. 의도적으로 재정의한 것이라면 괜찮겠지만, 변수 greeter가 이미 정의되어 있다는 사실을 인식하지 못한 경우에는 문제가 됩니다.

만약 코드의 다른 부분에서 greeter를 사용한 적이 있다면 뜻밖의 출력 결과에 놀랄 수 있습니다. 그리고 많은 버그를 발생시킬 수 있기 때문에 letconst가 필요하게 된 것이죠.

Let

var 선언에 대한 개선을 반영한 let이 현재 변수 선언에서 선호되고 있습니다. 방금 다뤘던 var의 문제점을 해결할 수 있었던 이유에 대해 살펴봅시다.

블록 범위 let

블록은 {}로 바인딩된 코드 청크인데요. 하나의 블록은 중괄호 속에서 존재하며, 중괄호 안에 있는 것은 모두 블록 범위입니다.

let으로 선언된 변수는 해당 블록 내에서만 사용가능합니다. 예를 들어 설명하자면:

   let greeting = "say Hi";
   let times = 4;

   if (times > 3) {
        let hello = "say Hello instead";
        console.log(hello);// "say Hello instead"
    }
   console.log(hello) // hello is not defined

중괄호로 감싸진 hello 변수가 정의된 블록 외부에서 helllo를 사용했더니 에러가 반환되는 것을 확인할 수 있습니다. let 변수는 블록 범위이기 때문이죠.

let은 업데이트될 수 있지만, 재선언은 불가능하다.

var와 마찬가지로 let으로 선언된 변수는 해당 범위 내에서 업데이트될 수 있습니다. 하지만, var와 달리 let 변수는 범위 내에서 다시 선언할 수 없습니다. 아래의 기능이 작동하는 동안:

    let greeting = "say Hi";
    greeting = "say Hello instead";

이와 같은 에러가 발생합니다:

    let greeting = "say Hi";
    let greeting = "say Hello instead"; // error: Identifier 'greeting' has already been declared

그러나 동일한 변수가 다른 범위 내에서 정의된다면, 에러는 더 이상 발생하지 않습니다.

    let greeting = "say Hi";
    if (true) {
        let greeting = "say Hello instead";
        console.log(greeting); // "say Hello instead"
    }
    console.log(greeting); // "say Hi"

오류가 없는 이유는 무엇일까요? 두 예제가 서로 다른 범위를 가지므로 서로 다른 변수로 취급되기 때문입니다. 따라서 var보다 let이 더 나은 선택이 될 수 있는 것이죠. let을 사용하는 경우라면, 변수가 범위 내에서만 존재하기 때문에 이전에 이미 사용한 적이 있는 변수 명에 대해서 더 이상 신경쓰지 않아도 좋습니다.또한, 범위 내에서 동일한 변수를 두 번 이상 선언할 수 없기 때문에 앞서 설명한 var의 문제가 발생하지 않습니다.

let의 호이스팅

var와 마찬가지로 let 선언은 맨 위로 끌어올려집니다. undefined(정의되지 않음)으로 초기화되는 var와 다르게 let의 키워드는 초기화되지 않습니다. 선언 이전에 let 변수를 사용하려고 시도한다면 Reference Error(참조 오류)가 발생할 것입니다.

Const

const로 선언된 변수는 일정한 상수 값을 유지합니다. const 선언은 let 선언과 몇 가지 유사점을 공유합니다.

블록 범위 const

let 선언처럼 const 선언도 선언된 블록 범위 내에서만 접근 가능합니다.

const는 업데이트도, 재선언도 불가능하다

const로 선언된 변수의 값이 해당 범위 내에서 동일하게 유지됨을 의미합니다. 업데이트하거나 다시 선언할 수가 없는 것이죠. const로 변수를 선언한 경우에는 다음과 같은 두 작업을 수행할 수 없습니다:

    const greeting = "say Hi";
    greeting = "say Hello instead";// error: Assignment to constant variable. 
    const greeting = "say Hi";
    const greeting = "say Hello instead";// error: Identifier 'greeting' has already been declared

따라서 모든 const 선언은 선언하는 당시에 초기화되어야 합니다.

개체의 경우는 다소 다른 점이 있는데요. const 개체는 업데이트할 수 없지만, 개체의 '속성'은 업데이트할 수 있습니다. const 객체를 다음과 같이 선언했다면:

    const greeting = {
        message: "say Hi",
        times: 4
    }

아래와 같은 작업은 불가능하지만:

    greeting = {
        words: "Hello",
        number: "five"
    } // error:  Assignment to constant variable.

다음의 코드는 가능합니다:

    greeting.message = "say Hello instead";

오류를 반환하지 않고 greeting.message 값이 업데이트됩니다.

const의 호이스팅

let과 마찬가지로 const 선언도 맨 위로 끌어올려지지만, 초기화되지는 않습니다.

세 가지 변수 선언법의 차이점에 대해서 총정리하자면:

  • var 선언은 전역 범위 또는 함수 범위이며, letconst는 블록 범위이다.
  • var 변수는 범위 내에서 업데이트 및 재선언할 수 있다. let 변수는 업데이트할 수 있지만, 재선언은 할 수 없다. const 변수는 업데이트와 재선언 둘 다 불가능하다.
  • 세 가지 모두 최상위로 호이스팅된다. 하지만 var 변수만 undefined(정의되지 않음)으로 초기화되고 letconst 변수는 초기화되지 않는다.
  • varlet은 초기화하지 않은 상태에서 선언할 수 있지만, const는 선언 중에 초기화해야한다.

Var, Let, Const에 대한 설명 영상


이게 전부랍니다. 질문 혹은 추가해야할 내용이 있다면 알려주세요.

읽어주셔서 감사합니다 :)