ReactJS를 작성할 떄에 미리 알아두면 좋은 ES6 문법들을 소개한다.

1. block scope

기존의 함수에 의한 스코프처럼 { }으로 감싼 내부에 별도의 스코프가 생성된다.

1
2
3
4
5
6
7
8
9
{
let a = 10;
{
let a = 20;
console.log(a); // (1)
}
console.log(a); // (2)
}
console.log(a); // (3)
1
2
3
4
5
6
let sum = 0;
for(let j = 1 ; j <= 10 ; j++){
sum += j;
}
console.log(sum); // (1)
console.log(j); // (2)
1
2
3
4
5
6
7
8
if(Math.random() < 0.5) {
let j = 0;
console.log(j); // (1)
} else {
let j = 1;
console.log(j); // (2)
}
console.log(j); // (3)

2. block scoped variables

let은 기존의 var를 대체하는 블락변수이고, const는 그 중 한 번 선언 및 정의되고 나면 값을 변경할 수 없는 변수이다.
블락 스코프 내부에서 선언된 let, const는 해당 스코프 내에서만 존재하며, 이들에 대해서는 ‘TDZ’가 존재한다.

TDZ (temporal dead zone, 임시사각지대) : 블락 스코프 내에서는 지역변수/상수에 대한 호이스팅이 이뤄지기는 하나, 선언된 위치 이전까지는 해당 변수/상수를 인식하지 못한다.

1
2
3
console.log(a); // (1)
let a = 2;
console.log(a); // (2)
1
2
3
4
5
var a = 10;
let b = 20;
console.log(a, b); // (1)
console.log(window.a, window.b); // (2)
console.log(this.a, this.b); // (3)
1
2
3
4
for(let j = 0; j < 5; j++){
console.log(j);
}
console.log(j); // (1)
1
2
const PI = 3.141593;
PI = 3.14; // (1)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const OBJ = {
prop1 : 1,
prop2 : [2, 3, 4],
prop3 : {a: 1, b: 2}
};
Object.freeze(OBJ);
OBJ.prop1 = 3;
OBJ.prop2.push(5);
OBJ.prop3.b = 3;
console.log(OBJ); // (1)
Object.freeze(OBJ.prop2);
OBJ.prop2.push(6);
console.log(OBJ); // (2)

링크 : Object.freeze 및 deep freezing

변수별 스코프 종속성

variables \ scope function block hoisting TDZ
let O O O O
const O O O O
var O X O X
function declaration O O X

함수선언문의 경우 sloppy-mode 모드에서는 block-scope의 영향을 받지 않고, strict-mode에서는 block-scope의 영향을 받는다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
foo();
function foo(){ console.log(1); }
{
foo();
function foo(){ console.log(2);}
}
}
foo();
'use strict';
{
foo();
function foo(){ console.log(1); }
{
foo();
function foo(){ console.log(2);}
}
}
foo();

3. arrow function

순수 함수로서의 기능만을 담당하기 위해 간소화한 함수.
=>의 좌측엔 매개변수, 우측엔 return될 내용을 기입한다. 우측이 여러줄로 이루어져있다면 { }로 묶을 수 있으며, 이 경우엔 명시적으로 return을 기술하지 않으면 undefined가 반환된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let getDate = () => new Date();
let sum = (a, b) => a + b;
let getSquare = a => { return a * a; }
let calc = (method, a, b) => {
switch(method) {
case 'sum': return a + b;
case 'sub': return a - b;
case 'mul': return a * b;
case 'div': return a / b;
}
return null;
}
console.log(getDate());
console.log(sum(4, 5));
console.log(getSquare(10));
console.log(calc('mul', 3, 4));
1
2
3
4
5
6
7
8
9
10
11
const obj = {
grades: [80, 90, 100],
getTotal: function() {
this.total = 0;
this.grades.forEach(v => {
this.total += v;
});
}
};
obj.getTotal();
console.log(obj.total); // (1)

4. rest parameter

  • 함수 파라미터에 일정하지 않은 값들을 넘기고자 할 경우에 유용.
  • arguments의 대체.
  • 배열의 얕은복사 목적으로 활용 가능.
1
2
3
4
function f(x, y, ...rest) {
console.log(rest); // (1)
}
f(1, 2, true, null, undefined, 10);
1
2
3
4
5
6
7
8
9
10
const sum = function(...arg) {
let result = 0;
for(let i = 0; i < arg.length ; i++){
result += arg[i];
}
return result;
};
/* const sum = (...arg) => arg.reduce((p,c)=> p+c); */
console.log(sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); // (1)

5. spread operator

문자열의 각 단어, 배열의 요소들이나 객체의 프로퍼티들(stage-2 proposal)을 해체하여 여러개의 값으로 반환해준다.

1
2
3
4
const str = 'lorem ipsum';
const arr = [20, 10, 30, 40, 50];
console.log(...arr); // (1)
console.log([...str]); // (2)
1
2
3
4
5
6
const originalArray = [1, 2];
const copiedArray = [...originalArray];
originalArray.push(3);
console.log(originalArray); // (1)
console.log(copiedArray); // (2)

6. default parameter

파라미터에 값을 할당하지 않거나 빈 값인 상태로 함수를 호출할 경우, 해당 파라미터를 지정한 기본값으로 인식하도록 해줌.
각 파라미터는 내부에서 let과 동일하게 동작하며, 따라서 TDZ가 존재한다.

1
2
3
4
function f(x = 1, y = 2, z = 3){
console.log(x, y, z); //(1)
}
f(4, undefined, 5);
1
2
3
4
5
function multiply(x = y * 3, y){
console.log(x * y);
}
multiply(2, 3); // (1)
multiply(undefined, 2); // (2)

7. Enhanced Object Literal

7-1. computed property key

프로퍼티의 키값에 표현식을 지정할 수 있다.

1
2
3
4
5
6
const suffix = ' name';
const iu = {
['last' + suffix] : '이',
['first' + suffix] : '지은'
};
console.log(iu); // (1)
1
2
3
4
5
6
7
8
9
10
11
12
const foo = (() => {
let count = 0;
return function(){
return count++;
};
})();
const obj = {
['bar' + foo()] : foo(),
['bar' + foo()] : foo()
};
console.log(obj); // (1)

7-2. property Shorthand

프로퍼티의 키와 값에 할당한 변수명이 동일한 경우, 키를 생략할 수 있다.

1
2
3
4
5
6
const x = 10, y = 20;
const obj = {
x,
y
};
console.log(obj); // (1)
1
2
3
4
5
6
7
8
9
function setInformation(name, age, gender){
return {
name,
age,
gender
};
}
const iu = setInformation('아이유', 23, 'female');
console.log(iu); // (1)

7-3. method Shorthand

메서드명 뒤의 : function 키워드를 생략할 수 있게 되었다.

1
2
3
4
5
6
7
8
9
10
11
const obj = {
name : 'foo',
getName() {
return this.name;
},
printName(name) {
console.log(this.getName());
}
};
console.log(obj.getName()); // (1)
obj.printName(); // (2)

7-4. Object.assign (ES5)

Object.assign()
첫 번째 파라미터의 객체에 두 번째 파라미터 및 그 이후의 각 객체들을 병합한다.

1
2
3
4
5
6
7
8
9
10
11
const targetObj = {
a: 1,
b: 2,
c: 3
};
const sourceObj = {
b: 4,
d: 5
};
Object.assign(targetObj, sourceObj);
console.log(targetObj, sourceObj); // (1)

이를 활용하면 객체 및 배열의 얕은 복사를 수행할 수 있다.

1
2
3
4
5
6
7
8
9
10
const originalObj = {
a: 1,
b: [2, 3, 4],
c: { d: 5, e: 6 }
};
const copiedObj = Object.assign({}, originalObj);
copiedObj.a = 11;
copiedObj.b[0] = 12;
copiedObj.c.d = 13;
console.log(originalObj, copiedObj); // (1)
1
2
3
4
5
6
const originalObj = {
a: [2, 3, 4],
b: { d: 5, e: 6 }
};
const copiedObj = Object.assign({}, originalObj, { b: { f: 7, g: 8 } });
console.log(copiedObj); // (1)

8. Destructuring Assignment

배열 혹은 객체를 해체하여 각각 변수에 할당한다.

1) 배열

1
2
3
4
5
const [ a, b, c ] = [ 1, 2, 3 ];
console.log(a, b, c); // (1)
const [ a, [ b, [ , c ], ], d ] = [ 1, [ 2, [ 3, 4 ], 5 ], 6 ];
console.log(a, b, c, d); // (2)

2) 객체

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const iu = {
name : '아이유',
age : 23,
gender : 'female'
};
const {
name: n,
age: a,
gender: g
} = iu;
console.log(n, a, g); // (1)
const {
name,
age,
gender
} = iu; // (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const {
name,
albums : {
regular,
irregular: {
'꽃갈피' : flower
}
}
} = {
name : '아이유',
albums: {
'regular' : ['Growing up', 'Last Fantasy', 'Modern Times'],
'irregular': {
'Real' : 2013,
'꽃갈피' : 2015,
'CHAT_SHIRE' : 2016
}
}
};
console.log(name, regular, flower); // (3)

9. template literals

여러줄 문자열, 보간(표현식 삽입) 등을 지원하는 새로운 형태의 문자열.

1
2
3
console.log(`a
bb
ccc`); // (1)
1
2
3
4
const a = 10;
const b = 20;
const str = `${a} + ${b} = ${ a + b }`;
console.log(str); // (1)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const characters = [{
name: 'Aria Stark',
lines: ['A girl has no name.']
}, {
name: 'John Snow',
lines: [
'You know nothing, John Snow.',
'Winter is coming.'
]
}];
const html = characters.reduce((prevCharacters, currentCaracter) => {
const { name, lines } = currentCaracter;
return `${prevCharacters}<article>
<h1>${name}</h1>
<ul>${lines.reduce((prevLines, currentLine) =>
`${prevLines || ''}
<li>${currentLine}</li>`
, '')}
</ul>
</article>
`}, '');
console.log(html); // (1)

10. class

Java의 그것과 비슷하지만 private 메서드가 없다.

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
32
33
34
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
toString() {
return `${this.name}, ${this.age}세`;
}
static logNames(persons) {
for (const person of persons) {
console.log(person.name, person.age);
}
}
}
class Employee extends Person {
static logNames(persons) {
for (const person of persons) {
console.log(person.name, person.age, person.title);
}
}
constructor(name, age, title) {
super(name, age);
this.title = title;
}
toString() {
return `${super.toString()}, (${this.title})`;
}
}
const park = new Employee('Park', 35, 'CTO');
const jung = new Employee('Jung', 30, 'CEO');
console.log(park.toString()); // (1)
Person.logNames([park, jung]); // (2)
Employee.logNames([park, jung]); // (3)

11. module - import / export

1) without ‘default’ export

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//------ lib.js ------
export const sqrt = Math.sqrt;
export function square(x) {
return x * x;
}
//------ main.js ------
import * as lib from './lib';
console.log(lib); // (1)
console.log(lib.square(5)); // (2)
console.log(lib.sqrt(4)); // (3)
/* or */
import { square, sqrt } from './lib';
console.log(square(5)); // (4)
console.log(sqrt(4)); // (5)

2) with ‘default’ export

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//------ lib.js ------
export default function lib() {
console.log('this is lib default function');
}
export const sqrt = Math.sqrt;
export function square(x) {
return x * x;
}
//------ main.js ------
import * as lib from './lib';
console.log(lib.default()); // (1)
console.log(lib.square(5)); // (2)
console.log(lib.sqrt(4)); // (3)
/* or */
import lib, { square, sqrt } from 'lib';
console.log(lib); // (4)
console.log(square(5)); // (5)
console.log(sqrt(4)); // (6)