함께 성장하는 프로독학러

1. 변수의 선언 (let, const) 본문

Programming/ES6

1. 변수의 선언 (let, const)

프로독학러 2018. 4. 3. 17:53

안녕하세요, 프로독학러 입니다.


모던 자바스크립트라고 불리우는 ES6 (ECMAScript 6)에 대해서 차근차근 공부해 봅시다.

* 공부에 도움이 된 자료들은 아래에 링크로 첨부하도록 하겠습니다.


오늘은 그 첫 번째 시간으로 ES6의 변수의 선언에 대해서 알아보도록 하겠습니다.


기존의 자바스크립트에서는 변수의 선언을 'var' 을 이용하여 하였습니다.

기존의 var 를 이용한 변수선언은 function scope입니다.

function scope 란, 함수 안에서 변수에 접근할 수 있는 것을 뜻합니다.

이해를 돕기위해 아래 예제를 보겠습니다.


1
2
3
4
5
6
7
8
function outter(){
    var out = 'outter 함수 안에 사는 변수';
    function inner(){
        console.log(out);
    }
}
 
console.log(out);
cs


변수 out 은 함수 outter안에서 var를 이용해 선언되었습니다. 

inner함수는 outter함수 안에 있기 때문에 outter함수 안에서 정의된 out에 접근할 수 있습니다.

그러나 함수 밖에서 console.log를 이용해 out변수에 접근하려하면

'Uncaught ReferenceError: out is not defined'

(out이 정의되지 않았다 라는) 에러메시지가 뜹니다.


반면 ES6의 변수 선언은 block scope입니다. 

block scope에서의 block은 '{}' 을 의미합니다.

번수에 접근할 수 있는 범위가 block('{}') 안 이라는 뜻입니다.


ES6에 변수 선언법은 두 가지가 있습니다.

let과 const인데, let은 변수 (변하는 수, 재할당이 가능)를 정의하는 것이고, 

const는 상수(번하지 않는 수, 재할당이 불가능)를 정의하는 것입니다. 

엄밀히 말하면 변수 선언법은 let이고, 상수 선언은 const이죠.


표현식은 다음과 같습니다.


let 변수명 = 값


const 상수명 = 값


let과 const는 앞서 말했듯이 block scope입니다.

이해를 위해 다음의 예제를 보겠습니다.


1
2
3
4
5
6
7
8
9
{
    let a = 10;
    {
        let a =20;
        console.log(a); // 20
    }
    console.log(a); // 10
}
console.log(a); // Uncaught ReferenceError: a is not defined




cs


위에서 부터 보면, console.log 중 맨 위의 값은 같은 블록안의 a변수를 참조하기 때문에 20이 찍힙니다.

그 아래에 있는 console.log 는 맨 위에 선언된 a 가 같은 블록에 위치하고 있으므로 10이 찍힙니다.

그리고 마지막에 있는 console.log 는 어떤 변수 a에도 접근할 수 없기 때문에 에러가 뜹니다. (모든 변수들은 블록안에서 선언됐지만 맨 마지막 콘솔로그는 블록의 바깥에 있다)


let은 위의 예제와 같이 재할당이 가능하지만 const는 변하지 않는 수이기 때문에 재할당을 하려고 하면 다음과 같은 에러가 뜹니다.


1
2
3
4
const a = '상수a';
console.log(a); // '상수a' 
const a = '변수a?'// Uncaught SyntaxError: Identifier 'a' has already been declared
console.log(a);
cs


그렇다면, 기존 자바스크립트의 var 문법을 이용하지 않고 ES6에서 let과 const를 새로 만든 이유는 무엇일까요?

기존 var를 이용한 변수의 선언은 다음과 같은 코드가 문제없이 실행됩니다.


1
2
3
4
console.log(a);
= 4;
var a; 
//4
cs


첫 줄에서 변수 a를 사용하지만 그 이전에 a는 정의 된 적 없습니다.

두 번째 줄에서 할당(초기화)을 먼저 하고, 이후에 세 번째 줄에서 선언합니다.

이는 호이스팅이 일어나기 때문에 가능한 코드입니다.

(*호이스팅이란 - 변수나 함수가 어디서 선언되든지 해당 스코프의 최상단에 위치하는것과 동일하게 동작하므로 같은 스코프 내에서는 어디서든 참조할 수 있도록 하는 것)

위의 예제는 호이스팅 덕분에 문제없이 작동하지만, 코드를 보는 사람이나 수정하는 사람으로 하여금 혼란을 야기할 수 있습니다.


1
2
3
4
console.log(a);
= 4;
let a; 
//Uncaught ReferenceError: e is not defined
cs


하지만 let과 const는 사용하기 전에 이미 선언이 되어 있어야 하므로 (tdz(temporal dead zone)) 위의 예제와 같은 코드에선 동작하지 않습니다.


또한 기존 자바 스크립트의 var을 이용한 for loop는 


1
2
3
4
5
for(var i = 0; i < 5; i += 1){
  setTimeout(function(){
    console.log(i);     
  }, 0);
}
cs


위의 예제에서 콘솔창에 5를 다섯 번 찍습니다. 

(setTimeout 메서드는 비동기작업이므로 브라우저가 stack에서 실행하지 않고 webapis로 넘겨작업하고 모든 stack이 끝난 뒤에 event loop에 의해서 다시 stack으로 올라와 작업이 완료된다. 즉, setTimeout의 리턴값은 for문이 다 종료된 후에 작업되므로 해당 시점의 i값인 5가 다섯 번 출력된다)

* 자바스크립트의 비동기적 처리에 대한 이해가 필요하시다면 다음의 링크를 참고해 주세요

<자바스크립트에서 비동기 작업을 처리하는 방식>


이를 해결하기 위한 간단한 방법은 let을 사용하는 것입니다.


1
2
3
4
5
for(let i = 0; i < 5; i += 1){
  setTimeout(function(){
    console.log(i);     
  }, 0);
}
cs


let은 block scope이기 때문에 stack의 단위가 블록이 되기 때문에 변수 i를 원하는대로 찍을 수 있습니다.

(0, 1, 2, 3, 4 가 차례로 찍힌다)


위와 같이 ES6의 let과 const를 이용하면 좀 더 이해하기 쉽고, 직관적인 코드를 짤 수 있습니다.


다음은 ES6의 좀 더 간단한 함수 정의 방법인 arrow function 에 대해서 알아보겠습니다.



**참고 자료 (항상 감사드립니다)

짱구의 기술블로그 - Chap27. 알쓸 ES6 

https://appear.github.io/2018/03/14/JavaScript/javascript_28/





Comments