EcmaScript2015 Syntax

ECMAScript2015(ES6) 기초 문법

ECMAScript 2015에는 많은 기능들이 추가 되었는데 그 중에 몇가지 기본적인 문법들을 정리해 본다.

  • let/const에 의한 블록 스코프
  • Map/Set/WeakMap/WeakSet에 의한 컬렉션
  • 형을 정의하는 클래스
  • 제너레이터/for..of
  • Promises
  • Template String Literals
  • 화살표 함수
  • 모듈

let 키워드

가장 먼저 변수 선언에 대하여 알아보자. 기존 Javascript 에서는 var 로 거의 통일되다 시피 변수를 선언하였다.
다만 var 의 문제점은 scope 에 있다.
var 의 scope 는 function 안에서 모두 접근 하게 되는데, 이는 타 언어 출신의 개발자를 헷갈리게 만들고 자칫 잘못하면 엄청난 버그를 만들어내는 방식이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var a = 1;   //  global variable

function Test1() {
console.log(a);
var b = 2;

if (true) {
var c = 3;
console.log(b);
}

console.log(c);
}

Test1();
// 1
// 2
// 3

위와 같이 Test1() 함수에서 전역변수인 a를 호출하고 변수 b를 지정하였다.
if 문안에서 변수 c를 지정하고 지역변수인 b를 호출하였다.
그리고 if문 밖에서 변수 c를 호출하였다.
이는 에러를 야기 시키지 않는가? 타 언어에서는 c가 if문 안에 있으니 undefined 라고 나올 수 있을꺼다 라고 하지만 자바스크립트에서는 그렇지 않다.
자바스크립트에서 변수의 범위는 function 즉 , 최초의 부모함수 (여기서는 Test1 함수) 가 되기 때문에 해당 코드의 실행 결과로 1 , 2 ,3 이 나타난다.

ES6 에서는
이를 보완하기 위해 let 이라는 block scope 의 변수를 선언하는 형식을 만들었다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let a = 1;
function Test1() {
console.log(a);

let b = 2;
if(true) {
let c = 3;
console.log(b);
}

console.log(c);
}

Test1();
// 1
// 2
// undefined

var 를 let 으로 변경하였다. a 는 여전히 전역변수가 되어있고 b 는 Test1 함수내에 어디서든 호출이 가능하며,
문제는 c 이다. 해당 함수를 실행하면 c는 나타나지 않는다.
let 으로 변경한 지금 c 변수는 if 문 안에서만 통용되도록 변경되었다. 타 언어의 변수 scope 와 같아진것 이다.
여기서 또 한가지 같은 범위 안이라면 var 는 이미 선언한 변수를 같은 이름으로 덮어 씌우는게 가능하다.
하지만 let 은 그렇지 않다.

1
2
3
4
5
6
7
8
9
var a = 1;
var a = 2;

console.log(a); // 2

let b = 1;
let b = 2;

console.log(b); // Type Error

위 코드 처럼 let 은 같은 범위내에서 같은 이름으로 덮어 씌우려 할 경우 Type Error 를 발생시킨다.

Const 키워드

Const 키워드는 let 과 같이 block scope 를 가지며, let 과 다른점은 상수로 선언된다는 점이다.
기존의 var 로 선언했을 시에는 프로그램 어디서나 해당 변수에 접근하여 값을 고칠 수 있다.
하지만 const 로 선언한다면 상수로 선언되기에 값을 변경시에는 에러가 발생하게 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
var r = 4;

var pi = 3.14;
console.log(r * r * pi); // 50.24

pi = 2.14
console.log(r * r * pi); // 34.24

const pi2 = 3.14;
console.log(r * r * pi2); // 50.24

pi2 = 2.14;
console.log(r * r * pi2); // Error

위 코드를 보면 var 로 선언한 pi 변수는 얼마든지 변경 할 수 있기에 단지 상수라고 생각하고 적어놨을 뿐 전혀 상수의 기능을 못 하고 있다.
하지만 const 로 선언한 변수는 값의 변경을 시도 했을 때 읽기 전용 예외 가 발생하며 변경이 되지 않는다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var a =  {
name: 'Tracer'
};
console.log(a.name); // Tracer

var a = {
age: '12'
};
console.log(a.age); // 12

const b = {
name: 'Over'
};
console.log(b.name); // Over

b.name = 'Watch';
console.log(b.name); // Watch

const b= {
name : 'OverWatch' // Error
};
console.log(b.name);

const 범위는 let 과 같으며 만약 객체를 const 로 선언했을 경우 객체안의 내용은 변경이 가능하지만 객체 자체를 재정의 하는 것은 불가능하다.

…배열 연산자(Spread Operator)

기존 자바스크립트에서 배열 값을 인자로 넘길때는 apply 메소드를 사용하여 넘겼다.
하지만 … 연산자를 사용하여 더욱 간단하게 인자값을 넘길 수 있다.

1
2
3
4
5
6
7
8
function Test1(a,b) {
return a + b;
};

var data = [1,2];

console.log(Test1.apply(null,data)); // 3
console.log(Test1(...data)); //3

… 연산자는 배열에 있는 값을 하나하나 꺼내서 개별적인 함수 인자로 만들어서 호출 한다.

… 연산자를 응용하면 다음과 같이도 사용할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let data1 = [1, 2, 3];
let data2 = [4, 5, 6];
let data3 = [...data1, ...data2, 7];

console.log(data3); // 1,2,3,4,5,6,7

data1.push(...data2);

console.log(data1); // 1,2,3,4,5,6

function add (a, b, c, d, e, f) {
return a + b + c + d + e + f;
}

console.log(add(...data1,...data2)); // 21

첫번째로 data3 배열은 data1 과 data2 의 배열을 포함시키는데 여기서 … 연산자를 사용하였다.
두번째로 배열에 배열을 push 할때 기존의 Array.prototype.push.apply(arr1,arr2) 가 아닌 좀 더 깔끔하고 간결하게 push 사용이 가능하다.
마지막으로 함수의 인자로 값을 넘길때 여러개의 배열을 … 연산자를 사용하여 넘길 수 있다.

배열

ES6 에서 간편해진 배열관련 문법들을 살펴보자.
위 … 연산자를 활용하는 방법과 그 외 기존에 쓰던 방법을 더욱 간단하게 표현할 수 있도록 ES6는 많은 변화가 있다.
먼저 배열에 값을 할당 할 때의 예제를 살펴보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// ES5
let array = [1,2,3];
let a = array[0];
let b = array[1];
let c = array[2];

console.log(a,b,c); // 1 2 3

// ES6
let array2 = [1,2,3];
let d, e, f;
[d,e,f] = array2;

console.log(d,e,f); // 1 2 3

// ES6
let array3 = [1,2,3];
let [g,h,i] = array;

console.log(g,h,i); // 1 2 3

배열 값을 할당하는 방법이 아주아주 간단해 진 걸 볼 수 있을 것이다.

여기서 배열 값의 건너뜀 과 응용하여 위에서 배운 … 연산자를 사용해보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let array = [1,2,3];
let[a, ,b] = array;

console.log(a,b); // 1,3

let array2 = [1,2,3];
let [c, ...d] = array2;

console.log(c); // 1
console.log(d); // 2,3

let array3 = [1,2,3,4];
let [e, , ...f] = array3;

console.log(e); // 1
console.log(f); // 3,4

위 코드를 보면 배열에 값을 지정할 때 중간값을 건너뛰는 것이 가능하다.

그리고 … 연산자를 이용하여 배열의 남은 값들을 다 포함시킬 수도 있고 , 역시 값을 건너뛰면서도 … 연산자가 사용가능 한 것을 볼 수 있다.

1
2
3
4
5
6
7
8
9
10
let array = [1,2];
let [a, b, c=3] = array;

console.log(a,b,c); //1,2,3

function test1(a = 1, b = 2, c = 3) {
return a + b + c;
}

console.log(test1()); // 6

첫번째 배열에서는 c에 기본값을 주고 출력하는 것을 볼 수 있다.
그리고 함수의 인자값에도 기본값을 주고 출력이 가능한 것을 확인 할 수 있다.

객체

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
30
//ES5

var Person = {
name: 'Korea',
age: '5000'
};

var name = Person.name;
var age = Person.age;

console.log(name,age); // Korea , 5000

//ES6
//변수명이 객체 값과 같아야 한다.
let Person2 = {
name2: 'Korea',
age2: '5000'
};

let {name2 , age2} = Person2;
console.log(name2,age2); // Korea , 5000

//ES6
//변수명을 다르게 주고 싶은 경우
let Person3 = {
name3: 'Korea',
age3: '5000'
};
let {name3: x , age3: y} = Person3;
console.log(x,y); // Korea , 5000

ES6 에서는 객체 값을 변수에 할당할 때 변수를 객체 값의 이름과 같이 만들어서 할당하는 방법이 있다.
그리고 마지막 부분은 변수의 이름을 객체 값과 같은 것이 아닌 다른 이름을 쓰고자 할때의 예제이다.

Arrow function

ES6 부터 Arrow function 이 추가 되었다.
(파라미터)=> {함수 본체};

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//ES5
var Test1 = function(a,b) {
return a + b;
};

console.log(Test1(1,2)); // 3

//ES6
let Test2 = (a,b)=> {
let result = a + b;

return result;
};

console.log(Test2(1,2)); // 3

//ES6
let Test3 = (a, b)=> (a + b);

console.log(Test3(1,2)); // 3

코드를 보면 알 수 있듯이 함수를 간결하게 표현할 수 있도록 바뀌었다.
함수의 return 문이 하나인 경우에 3번째 예제처럼 한줄로 만들 수도 있다.

Arrow function 의 가장 중요한 특징은 this 값의 scope 변경이다. 예제를 살펴보자.

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
30
31
var a = 1;
console.log(this === window); // true
console.log(this.a); // 1

function test1() {
console.log(this === window); // true
}

var object1 = {
test: function() {
console.log(this === object1); // true

(function() {
console.log(this === object1); // false
console.log(this.a); // 1
}());
} ,
test2: function() {
console.log(this === object1); // true

var that = this;

(function() {
console.log(that === object1); // true
})();
}
};

test1();
object1.test();
object1.test2();

위 코드는 es5 에서 this 의 scope 를 나타낸다. es5 에서는 this 의 scope 가 기본적으로 전역객체 (브라우저라면 window)
를 가르키고 있으며 함수를 만들어도 this 값은 여전히 window 객체를 가리키고 있다.
하지만 object 를 만들게 되면 this 는 자신을 호출한 object 를 가리키게 되며 object1 의 test 를 보면 알 수 있다.
이런 부분은 callback 함수를 만들 었을 때 문제가 생긴다.
test 의 내부 함수를 보면 해당 함수의 this 는 object1 을 가리키지 않고 여전히 window 객체를 가리키고 있다.
왜 그런고 하니 내부함수는 객체의 멤버 메서드가 아닌 단지 호출된 함수 일 뿐이다.
그럼 function 이라는 놈을 가지고 있는 부모 객체는 누구인가? 바로 전지전능한 window 객체가 된다.
그렇기 때문에 내부 함수에서는 this 가 global 객체 를 가리키게 된다.

이를 해결하기 위해 object1 의 test2 함수처럼 함수 선언시에 this 를 임의의 변수에 넣어서 쓰는 방법을 사용한다.
( 보통 that 또는 self , _this 등의 이름을 쓴다. ) 그리고 내부 함수에서는 이를 호출하여 사용하게 되는데 , arrow function 에서는 이런 부분이 해결된다.

위 코드의 object1 을 arrow function 을 이용하여 만들어 보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
let a = 1;
let object1 = {
test: function() {
console.log(this === object1); // true

(() => {
console.log(this === object1); // true
console.log(this.a); // undefined
})();
} ,
test2: function() {
console.log(this === object1); // true

(() => {
console.log(this === object1); // true
})();
}
};

object1.test();
object1.test2();

코드의 결과를 보면 내부 함수의 this 가 가리키는 곳이 window 가 아닌 object1 으로 바뀌었다.
이는 이전의 this 범위와 다르게 자신을 둘러싸는 문맥의 this 값을 가진다.
참고로 Arrow function 은 new 연산자를 사용할 수 없다.

객체 리터럴

ES6 에서 객체 리터럴로 프로퍼티를 생성하는 새로운 구문이 있다.

1
2
3
4
5
6
7
8
9
10
11
12
let first = 'one';
let second = 'two';

let object = {first, second};
console.log(object.first); // one
console.log(object.second); // two

let third = 'three';
let object2 = {object , third};
console.log(object2.object.first); // one
console.log(object2.object.second); // two
console.log(object2.third); // three

2진수 , 8진수 표현 방식

ES6 에서의 2진수와 8진수 표현 방식을 보자. 예전에는 자바스크립트 만으로는 2진수를 나타낼 방법은 없었다.
하지만 ES6 에서는 숫자앞에 0b 를 붙이면 자바스크립트 엔진이 2진수로 처리하게 된다.
더불어 8진수를 표현할 때 숫자 앞에 0을 붙여서 표기를 하였다. 하지만 이는 초심자에게 헷갈릴 수 있다고 판단, 0 이 아닌 0o 를 붙이는 것 으로 변경되었다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//ES6   2진수 표현
let a = 0b00001111;
let b = 15;

console.log(a === b); //true
console.log(a); //15

//ES5 8진수 표현
var aa = 017;
var bb = 15;

console.log(aa === bb); //true
console.log(aa); //15

//ES6 8진수 표현
let aaa = 0o17;
let bbb = 15;

console.log(aaa === bbb); //true
console.log(bbb); //15

참조

공유하기