(ES6) - 02 let, const

  • SUNGMIN SHIN
  • 29 Minutes
  • 2017년 9월 13일

[ ECMA Script6 ]

(http://book.naver.com/bookdb/book_detail.nhn?bid=11556385)


2.1 var 키워드


변수는 크게 로컬(지역)변수와 글로벌(전역)변수로 구분하는데 이는 스코프 때문으로 지역 변수는 함수 또는 오브젝트를 스코프로 사용하려는 의도이며 전역 변수는 프로그램 전체에서 공용으로 사용하려는 목적 입니다.

1
2
3
4
5
6
7
8
9
10
11
12
/* [소스 let-1] */

// var 키워드를 생략하여 글로벌 변수로 one을 선언
one = 100;
function get(){
// 함수 내부에 존재하지만 var 키워드를 생략하여 글로벌 변수의 값을 변경
one = 300;
// 로컬 변수 one이 존재하지 않기 때문에 글로벌 변수 one을 참조
console.log('함수:', one);
}
get();
console.log('글로벌', one);

이 예제에서 변수 one은 클로저로 사용하기 위한 의도적인 접근일 수 있지만 다른 프로그램에서 같은 이름의 변수를 사용하는 경우 의도하지 않는 값이 설정될 수 있습니다.

글로벌 변수의 오해

글로벌 오브젝트에 작성한 변수는 글로벌 오브젝트가 스코프 입니다. 즉 글로벌 오브젝트에 작성 했으므로 글로벌 변수라고 부르는 것이지 글로벌 오브젝트에서 보면 로컬 변수 입니다.
var 키워드를 사용하지 않으면 글로벌 변수로 간주된다는 점으로 인해 작성하지 않고 사용하기도 하지만 글로벌 변수가 var 키워드를 사용하지 않는 것은 아닙니다.

글로벌 변수가 편리할 수 있지만 객체지향의 관점에서는 단점이 됩니다.
이는 마치 내가 사는 집(글로벌 오브젝트)의 물건(글로벌 변수)을 아무나 사용하는 모습으로 다른 사람이 내 물건을 사용하려면 나에게 허락을 받거나 내가 다른 사람들이 사용할 수 있도록 조치를 취해야 합니다.
함수 안에서 글로벌 오브젝트에 작성된 글로벌 변수를 사용할 수 있지만 다른 프로그램에서 값을 변경할 수도 있다는 위험은 감수해야 합니다.

use strict의 사용

use strict는 ES5의 새로운 기능으로 일종의 엄격 모드입니다.
프로그램을 엄격한 운용 컨텍스트 안에서 실행시킬 수 있게 끔 해주고 정의되지 않은 변수를 사용하거나 변수나 객체를 삭제하는 경우, 함수 매개변수에 중복된 이름 등 올바르지 않은 문법들에 대해 좀 더 많은 예외를 발생 시킵니다.
사용 영역은 글로벌, 함수(지역)으로 나누어 사용할 수 있으며 사용 시 최상위에 선언되어야 합니다.

1
2
3
4
5
6
7
8
9
10
// 전역에서 선언
'use strict'

function func1(){
// 지역(함수)에서 선언
'use strict'
.
.
.
}

(참고 - http://hmmim.tistory.com/5)


2.2 let 키워드


1
let sports = '축구';

위 형태가 let 키워드로 변수를 선언한 것 입니다.
var 키워드의 문제점을 해결하기 위한 것으로 아래와 같은 특징이 있습니다.

  1. 함수 안에 작성한 let 변수는 함수가 스코프(함수에 중괄호가 존재하므로 기존과 동일)
  2. 함수 안에 if등 블록(중괄호) 내에 선언했다면 중괄호가 스코프
  3. 블록 밖에 값은 이름의 변수가 있어도 스코프가 다르므로 각각의 변수에 값을 선언할 수 있으며 값이 유지됩니다
  4. 블록 안에 블록을 계층적으로 작성하면 각각의 블록이 스코프가 됩니다
  5. 같은 스코프에서 같은 이름의 let 변수를 선언할 수 없습니다(에러 발생)
  6. let 변수는 호이스팅이 되지 않습니다.


2.3 let 변수 작성 방법


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
'use strict'
// 초기 값 없이 선언 가능
let book;
// 초기 값을 포함한 선언
let sports = '축구';
// 선언된 값의 변경
sports = '농구';
// var 키워드처럼 컴마로 구분하여 연속으로 생성 가능
let one = 1, two = 2, three;

/*
// let 키워드를 사용하여 동일한 이름의 변수는 생성 불가
let sports = '배구';
// 연속 생성 시 키워드를 생략하지 않으면 에러 발생
let four = 4, let five = 5;
let dix = 6, var seven = 7;
*/


2.4 블록 스코프


let 변수를 선언하는 가장 큰 목적은 스코프 관리 입니다.
블록 스코프의 기준은 블록(중괄호)이며 블록 안과 밖의 변수 이름이 같더라도 스코프가 다르므로 변수가 선언되고 각 변수에 할당된 값이 대체되지 않고 유지됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
/* [소스 let-3] */

// let 키워드로 선언하여 블록 단위 스코프를 가짐
let sports = '축구';

if (sports) {
let sports = '농구';
// 로컬 변수로 sports가 존재하므로 로컬변수의 값을 반환
console.log('블록: ', sports);
}
// 글로벌 변수의 값을 반환
console.log('글로벌: ', sports);


2.5 let과 this 키워드


1
2
3
4
5
6
7
8
9
/* [소스 let-this] */

var music = '음악';
// 여기서의 this는 상위 객체인 window 객체를 참조
console.log(this.music);

// let 키워드를 사용하면 window객체에 속하지 않음
let sports = '축구';
console.log(this.sports);

위 예제에서 현재 스코프는 글로벌 오브젝트이고 this가 글로벌 오브젝트를 참조합니다.
(글로벌 오브젝트가 window오브젝트는 아니지만 window 오브젝트로 글로벌 변수에 접근할 수 있음)
즉 this가 window 오브젝트를 참조하는데 let 키워드로 선언된 변수는 스코프가 글로벌 오브젝트더라도 window 오브젝트에 속하지 않는 차이가 있습니다.


2.6 function


1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* [소스 let-function] */

let sports = '축구',
music = '재즈';

function get(){
let music = '클래식';

// 지역 변수가 존재하므로 지역 변수의 값을 참조
console.lot(music);
// 전역 변수만 존재하므로 전역 변수의 값을 참조
console.lot(sports);
}
get();

함수의 안과 밖은 다른 스코프를 가지므로 변수 music의 값은 로컬 변수의 값을 참조 합니다.
이와 같이 let 변수도 가장 가까운 스코프에 있는 변수를 먼저 사용 합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/* [소스 let-function-this] */

'use strict';

var sports = '축구';
let music = '재즈';

function get(){
var sports = '농구';
let music = '클래식';

console.log('1:', sports);
console.log('2:', this.sports);
console.log('3:', this.music);
}

window.get();
/*
'농구'
'축구'
undefined
*/

// use strict가 선언되지 않았다면 정상적으로 출력
get();
/*
'농구'
error
*/

strict 모드에서 window.get()과 같이 get()앞의 오브젝트 위치에 window를 작성하는 경우 get() 함수 안에서 this가 window를 참조합니다. (여기서의 차이는 ES6가 아닌 ES5의 strict 모드의 제한)


2.7 try-catch


1
2
3
4
5
6
7
8
/* [소스 let-try] */

let sports = '축구';
try {
let sports = '농구';
console.log(sports);
} catch(e) { };
console.log(sports);

try-catch문에서 try 블록 기준으로 블록 스코프를 가지며 catch 블록은 스코프를 갖지 않고 try 스코프에 속합니다.(?)

테스트

1
2
3
4
5
6
7
8
9
10

try {
let test = 10;
// 에러 발생
alert(none);
} catch(e) {
// catch 문 내에서 let 키워드를 사용하여 try 내부의 동일한 변수명으로 생성하였으나 문제 X
let test = 20;
console.log(test);
}


2.8 switch-case


1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* [소스 let-switch] */

var count = 2;
let sports = '축구';

switch(count) {
case 1:
let sports = '농구';
// 로컬 변수가 존재하므로 로컬 변수를 참조
console.log(sports);
};

// 글로벌 변수를 참조
console.log(sports)

switch-case 문에서 switch 블록이 블록 스코프이며 case는 별도의 스코프를 갖지 않고 switch 스코프에 포함됩니다.(중괄호가 변수 스코프의 기준인 것을 확인할 수 있습니다.)


2.9 호이스팅(hoisting)


자바스크립트에서는 소스 코드를 위에서 아래로 순차적으로 실행 합니다.하지만 함수 선언문은 호출하는 코드를 호출될 함수의 위에 작성해도 호출이 되는데 이를 호이스팅이라고 합니다.
var 키워드로 생성된 변수도 선언 자체에 한해서 호이스팅이 일어나는 데 반면 let 키워드로 생성된 변수는 호이스팅이 일어나지 않습니다.

1
2
3
4
5
6
7
8
9
/* [소스 let-hoisting] */

// var 키워드는 선언에 한해서 호이스팅이 발생하므로 undefined를 출력
console.log(sports);
var sports = '스포츠';

// let 키워드는 호이스팅이 발생하지 않으므로 에러
console.log(music);
let music = '음악';


2.10 for


for문에서의 let 키워드의 가장 큰 특징은 var와 달리 반복할 때마다 스코프를 가진다는 것 입니다.

비교

var 키워드를 사용하는 경우(event)

let 키워드를 사용하는 경우(event)


2.10 const


const 키워드로 할당된 값을 상수로 값을 변경할 수 없습니다.
상수의 개념이므로 이름을 중복하여 사용할 수 없으며 자바스크립트에서는 관계적으로 상수의 구분을 위해 상수는 영문 대문자로 표기하였지만 const키워드를 사용하면 키워드만으로도 구분할 수 있게 되었습니다.

1
2
3
4
5
6
7
8
9
10
11
/* [소스 const-1] */

// const 키워드로 상수 SPORT를 선언
const SPORTS = '축구';

try {
// 상수에 값을 재할당 할 수 없으므로 catch문 실행
SPORTS = '농구';
} catch(e) {
console.log('const는 재할당 불가');
}

단 위의 예제에서 try문 내 SPORTS에 let 키워드를 사용한다면 블록 스코프를 갖게 되므로 오류가 발생하지 않습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/* [소스 const-2] */

// 상수 obj 선언
const obj = {
language: '한글'
};

try {
// obj는 상수이므로 에러 발생
obj = {};
} catch(e) {
console.log('const는 재할당 불가');
}

// const 키워드로 선언하더라도 객체 내 프로퍼티의 값은 변경할 수 있음
obj.language = '영어';
console.log(obj.language);

const 키워드로 선언된 obj에 object를 할당할 수는 없지만 프로퍼티의 값을 할당할 수는 있습니다. (프로퍼티를 추가하는 것도 가능)


요약


let

  • 블록(중괄호) 스코프를 갖는다
  • 호이스팅이 일어나지 않는다.
  • 같은 스코프 안에서 let 키워드를 사용하여 동일한 이름의 변수를 선언할 수 없다.
  • 글로벌 스코프에서 선언되어도 window객체에 포함되지 않는다.
  • try-catch문에서 try 블록 기준으로 블록 스코프를 가지며 catch 블록은 스코프를 갖지 않고 try 스코프에 속합니다.(?)

const

  • const 키워드로 상수를 선언할 수 있다.
  • 호이스팅이 일어나지 않는다.
  • 상수는 값을 변경하거나 동일한 이름의 변수나 상수를 할당할 수 없음
  • 글로벌 스코프에서 선언되어도 window객체에 포함되지 않는다.
  • 단 객체(배열)인 경우 프로퍼티를 추가, 변경, 삭제할 수 있습니다.