var, let, const의 차이점

Javascript

본 게시물은 Var, Let, and Const – What’s the Difference? 글을 번역하였습니다.


ES2015(ES6)와 함께 새로운 기능들이 많이 출시되었다. 많은 자바스크립트 개발자들이 현재 ES6의 새로운 기능들에 익숙해졌고, 자주 사용하고 있다.

물론 이 말이 맞을 수도 있지만, ES6의 특성 중 일부는 여전히 일부 개발자들에게 어려운 과제로 남아있다.

ES6와 함께 제공되는 주요 기능 중 하나는 변수 선언에 사용할 수 있는 letconst 이다. 문제는, 우리가 사용해온 기존의var 과 차이점이 무엇인지 정확히 모르는 것이다. 만약 이 차이점에 대해 여전히 명확하지 않다면, 이 글을 반드시 읽어주길 바란다.

이 글에서는 var, letconst의 스코프(범위), 사용 방법 및 호이스팅에 대해 논의한다.


Var

ES6가 등장하기 전에는 대부분 var 을 사용했다. 그러나 var로 선언된 변수에는 몇몇 문제가 있었고, 이를 보완하기 위해 새로운 변수 선언 방식이 등장해야 했다. 이 문제에 대해 논의하기 전에 var 에 대해 좀 더 자세히 알아보도록 하자.

Var의 스코프

스코프(scope)는 기본적으로 변수를 사용할 수 있는 위치를 의미한다. var 선언은 전역(global) 변수로 사용되거나 함수, 지역(local) 변수로도 사용된다.

var 변수가 함수 외부에 선언되면 스코프는 전역(global)이 된다. 즉, 함수 블록 외부에 var로 선언된 모든 변수를 전체 window에서 사용할 수 있다.

var가 함수 내에서 선언되면 함수 스코프를 갖는다. 즉, 해당 함수 내에서만 사용 가능하며, 액세스할 수 있다.

더 자세히 이해하기 위해 아래 예를 살펴보자.

var greeter = 'hey hi'

function newFunction() {
  var hello = 'hello'
}

여기서 greeter는 함수 밖에 존재하는 전역 스코프이며, hello는 함수 내에 있으므로 함수 스코프이다. 그래서 함수 밖에서는 변수 hello에 접근할 수 없다. 아래 예시를 보자:

    var 테스터 = "hey hi";

    기능 newFunction() {
        var hello = "hello";
    }
    console.log(hello); // 오류: hello가 정의되지 않았습니다.

함수 밖에서는 hello를 사용할 수 없기 때문에 오류가 발생한다.

var는 재선언 및 업데이트가 가능하다

즉, var 는 아래와 같이 동일한 스코프 내에서 변수 재선언을 할 수 있고 오류가 발생하지 않는다.

var greeter = 'hey hi'
var greeter = 'say hello'

그리고 업데이트 또한 가능하다:

var greeter = 'hey hi'
greeter = 'say hello'

var의 호이스팅

우선 호이스팅에 대해서 알아보자. 호이스팅의 사전적 의미는 아래와 같다:

JavaScript에서 호이스팅(hoisting)이란, 인터프리터가 변수와 함수의 메모리 공간선언 전에 미리 할당하는 것을 의미합니다. var로 선언한 변수의 경우 호이스팅 시 undefined로 변수를 초기화합니다. 반면 letconst로 선언한 변수의 경우 호이스팅 시 변수를 초기화하지 않습니다.

호이스팅을 설명할 땐 주로 “변수의 선언과 초기화를 분리한 후, 선언만 코드의 최상단으로 옮기는” 것으로 말하곤 합니다. 따라서 변수를 정의하는 코드보다 사용하는 코드가 앞서 등장할 수 있습니다. 다만 선언과 초기화를 함께 수행하는 경우, 선언 코드까지 실행해야 변수가 초기화된 상태가 됨을 주의하세요.

*출처: 호이스팅 - MDN Web Docs

호이스팅(hoisting)변수와 함수 선언이 코드 실행 전에 해당 스코프의 맨 위로 이동하는 자바스크립트 메커니즘이다. 즉, 만약 아래와 같은 코드를 실행하면:

console.log(greeter)
var greeter = 'hello'

다음과 같이 해석된다:

var greeter
console.log(greeter), // greeter is undefined
  (greeter = '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"

times > 3는 true를 반환하기 때문에, greeter는 처음에 정의된 'hey hi' 대신, "say Hello instead"로 다시 정의된다. greeter를 다시 정의하려는 경우에는 문제가 되지 않지만 greeter가 이전에 이미 정의되어 있다는 것을 인식하지 못하는 경우에는 문제가 된다.

즉, 코드의 다른 부분에서 greeter를 사용한 경우, 의도하지 않은 값이 출력될 수 있으며, 코드에 많은 버그가 발생할 수 있다. 이것이 바로 letconst이 필요한 이유이다.


Let

요즘 변수 선언에는let이 더 선호된다. let은 앞서 설명한 var의 문제점들을 해결해주는데, 어떻게 해결하는지 더 자세히 알아보자.

let은 블록 스코프 내에서 작동한다.

**블록(block)**은 {}으로 바인딩된 코드 덩어리이다. 즉, {} 안에 있는 것은 모두 블록이다.

따라서 블록에 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를 사용하면 undefined오류가 반환된다. 이는 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"

왜 오류가 나지 않을까? 두 인스턴스의 스코프가 다르기 때문에 아예 다른 변수로 취급되기 때문이다.

덕분에 letvar보다 더 선호된다. let을 사용할 때는 변수가 해당 스코프 내에서만 존재하므로, 이전에 동일한 변수명을 사용한 적이 있는지 없는지 신경쓸 필요가 없다.

또한 변수는 한 스코프 내에서 두 번 이상 선언될 수 없기 때문에 앞에서 얘기한 var의 문제는 더 이상 발생하지 않는다.

let 호이스팅

var처럼, let은 선언을 최상단으로 끌어올린다. 하지만 undefined으로 초기화되는 var와 달리 let 변수는 초기화되지 않는다. 따라서 선언 전에 let 변수를 사용하려고 하면 Reference Error가 발생한다.


Const

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

const 선언은 블록 스코프이다.

let 선언과 마찬가지로, const 선언은 선언된 블록 내에서만 접근할 수 있다.

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로 선언된 **객체(object)**에 대해서는 다소 다르게 동작한다. 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 변수는 업데이트와 재선언 모두 불가하다.
  • 세 가지 모두 최상단으로 호이스팅된다. 차이점은, varundefined 상태로 초기화되지만, letcont 는 초기화되지 않는다.
  • varlet은 초기화하지 않고 선언할 수 있지만, const는 선언과 동시에 초기화해야 한다.


출처




Profile picture
@김하연
4년차 프론트엔드 개발자 입니다. 사용자 경험 개선, 코드의 재사용성, 읽기 쉬운 코드에 집중하여 개발합니다.
AboutGithub LinkedinResume
Loading script...