# let, const

## var, let, const

기존에 사용하던 변수 선언 방식은 다음과 같이 var 키워드를 사용한다.

```javascript
var a = 10;
var b = "hello";
```

이 변수 선언 방식은 다음과 같은 문제가 있다.

* 변수의 중복 선언이 가능하다.
* 변수가 없는 경우와 변수가 선언만 된 경우 모두 undefined를 반환한다
* 함수 레벨 스코프를 가진다.

위 문제들을 해결하기 위하여 const와 let이라는 키워드가 등장하였다.

* const : 불변(immutable) 변수 선언 키워드
* let : 가변(mutable) 변수 선언 키워드

## var 중복 선언

```javascript
var a = 10;
var a = "hello";
var a = 12 + 345;
console.log(a);
```

위 코드를 실행하면 마지막에 선언한 a의 계산 결과인 357이 콘솔에 출력된다. 자유로운 자바스크립트 문법 체계에서는 문제가 되지 않을 수 있으나 이는 개발자를 혼란스럽게 만든다.

```javascript
var a = 10;
a = "hello";
a = 12 + 345;
console.log(a);
```

위와 같이 작성하면 a의 값이 변경되었음을 코드로 짐작할 수 있다. **const**와 **let** 키워드를 사용하면 중복 선언이 불가능하다.

```javascript
const a = 10;
const a = "hello";//Uncaught SyntaxError : Identifier 'a' has already been declared
const a = 12+345;//Uncaught SyntaxError : Identifier 'a' has already been declared
console.log(a);
```

```javascript
let a = 10;
let a = "hello";//Uncaught SyntaxError : Identifier 'a' has already been declared
let a = 12+345;//Uncaught SyntaxError : Identifier 'a' has already been declared
console.log(a);
```

## undefined 이슈

var로 변수를 선언할 경우 **undefined 이슈**가 발생할 수 있다.

```javascript
console.log(b);//undefined
var b;
console.log(b);//undefined
```

위 코드를 실행하면 변수 선언 전, 후가 동일하게 undefined가 나온다. 이는 var로 선언한 변수가 호이스팅(hoisting) 되기 때문이다.

> ### 호이스팅
>
> JavaScript에서 **호이스팅**(hoisting)이란, 인터프리터가 변수와 함수의 메모리 공간을 선언 전에 미리 할당하는 것을 의미합니다. `var`로 선언한 변수의 경우 호이스팅 시 `undefined`로 변수를 초기화합니다. 반면 `let`과 `const`로 선언한 변수의 경우 호이스팅 시 변수를 초기화하지 않습니다.
>
> 호이스팅을 설명할 땐 주로 "변수의 선언과 초기화를 분리한 후, 선언만 코드의 최상단으로 옮기는" 것으로 말하곤 합니다. 따라서 변수를 정의하는 코드보다 사용하는 코드가 앞서 등장할 수 있습니다. 다만 선언과 초기화를 함께 수행하는 경우, 선언 코드까지 실행해야 변수가 초기화된 상태가 됨을 주의하세요.
>
> 출처 - MDN Web docs (<https://developer.mozilla.org/ko/docs/Glossary/Hoisting>)

호이스팅은 자바스크립트가 실행되는 가장 일반적인 방법이었으나, 프로그램이 점점 고도화되면서 변수에 있어서 가독성이 떨어진다는 단점이 발생하게 되었다.

const는 불변(immutable)이므로 반드시 값이 대입되어야 한다.

```javascript
const b;//Uncaught SyntaxError: Missing initializer in const declaration
```

또한, 중복 선언도 불가능하다.

```javascript
const b = "hello";
const b = "hi";//Uncaught SyntaxError: Identifier 'b' has already been declared
```

선언 전에 접근할 수도 없다.

```javascript
console.log(b);//Uncaught ReferenceError: b is not defined
const b = "hello";
```

let은 가변이므로 선언만 해도 문제가 발생하지 않는다.

```javascript
let b;//undefined
```

하지만 추가 선언을 하면 오류가 발생하므로 변수 선언은 한 번만 될 것이라 믿을 수 있다.

```javascript
let b;
let b;//Uncaught SyntaxError: Identifier 'b' has already been declared
```

let 역시 const와 마찬가지로 선언 전에 접근할 수 없다.

```javascript
console.log(b);//Uncaught ReferenceError: b is not defined
let b = "hello";
```

## var 함수 레벨 스코프

var 키워드로 선언된 변수는 함수 상단에 호이스팅된다.

<div align="left"><figure><img src="https://4208234536-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_TNZwLuHV9ipYLbvRq%2Fuploads%2FetWzWnSojMktfI1nVq14%2Fhoisting.png?alt=media&#x26;token=35419ae7-689f-451e-b8dd-20b9d1907591" alt=""><figcaption></figcaption></figure></div>

위 이미지 코드대로 함수를 만들어 실행하면 다음과 같이 출력된다.

```
10 '홀수' undefined
```

하지만 이는 정상적인 출력이라 보기 어렵다. 코드에는 함수 뿐 아니라 if와 else같은 블록(block) 레벨 스코프도 존재하기 때문이다.

<div align="left"><figure><img src="https://4208234536-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_TNZwLuHV9ipYLbvRq%2Fuploads%2FO5z76J2cOGDZthz7Aquw%2Fhosting-scope.png?alt=media&#x26;token=016cd447-8b28-4f55-be04-e821012eb391" alt=""><figcaption></figcaption></figure></div>

현대 프로그래밍에서는 함수 레벨 스코프 뿐 아니라 블록 레벨 스코프도 중요하게 간주한다. 따라서 var로 변수를 선언하면 스코프의 혼동이 올 수 있어 명확한 코드 작성이 어렵다.

const 또는 let으로 코드를 변경하면 블록 레벨 스코프 범위로 제한하여 사용할 수 있으며, 선언 전에 접근할 수 없다.

<pre class="language-javascript"><code class="lang-javascript"><strong>function tmpFunc(){
</strong>    const a = 10;
    if(a % 2 == 0){
        const b = "짝수";
    }
    else {
        const c = "홀수";
    }
    console.log(a);//10
    console.log(b);//Uncaught ReferenceError: b is not defined
    console.log(c);//Uncaught ReferenceError: c is not defined
}
</code></pre>

## 결론

특별한 이유가 없다면 **const**와 **let**을 사용하여 변수를 처리하는 것이 좋다.
