# ES6+

간단 정리


# destructuring

배열의 경우 순서가 중요합니다.

const [a, b] = [1, 2]; //a: 1 b: 2

객체의 경우는 키 이름이 중요합니다.

const {b, a} = {a: 1, b: 2}; //a: 1, b: 2

함수 파라미터도 destructuring 할 수 있습니다.

function A({a, b}) {
  return a + b;
}
A({a:1, b:2}); //3

# rest

디스트럭쳐링이나 함수 파라미터에서 나머지 변수들을 유용하게 컨트롤할 수 있습니다.

아래 예제 2개에서는 destructuring과 함께 썼지만, rest라는 변수 이름에 주목하시면 됩니다.

const [a, b, ...rest] = [1, 2, 3, 4]; //a: 1 b: 2, rest: [3, 4]

객체의 경우는 키 이름이 중요합니다.

const {b, a, ...rest} = {a: 1, b: 2, c: 3, d: 4}; //a: 1, b: 2, rest: { c: 3, d: 4 }

함수 파라미터에도 rest 구문을 사용할 수 있습니다.

function A(a, ...rest) {
  return rest;
}
A(1, 2, 3, 4); //[2, 3, 4]

# spread

spread는 rest와 반대로 생각하시면 편리합니다.

const obj = {
  a: 1,
  b: 2,
  c: 3,
};

const extObj = {
  ...obj, //spread
  d: 4
};

console.log(extObj); // {a: 1, b: 2, c: 3, d: 4}

배열도 당연히 같은 방법으로 사용합니다.

const arr1 = [1, 2];
const arr2 = [...arr1, 3, 4]; // [1, 2, 3, 4]

# for in, for of

아래 예제에서 보이는 것처럼,

for in 구문은 custom 프로토타입을 포함한 모든것을 순회하고,

for of 는 콜렉션에 대해서만 순회합니다.

[Symbol.iterator] 속성이 있는 모든 컬렉션 요소

Array.prototype.someArrayFunc = () => {};

let someArray = [1, 2, 3];
someArray.boseok = 'boseok123';

for (let i in someArray) {
  console.log(i); // 0,1,2 'boseok', 'someArrayFunc'
}

for (let i of someArray) {
  console.log(i); //1,2,3
}

in 구문은 객체의 value를 나열하는게 아니라, key를 나열한다고 생각하면 됩니다.


# Map

Array.prototype.map은 여기서..

es6에는 map 객체가 새로 추가됐다.

new Map(iterable);

기존 object와 비슷하지만 여러 문제를 해결해주는객체다.

기존 object처럼 키-밸류를 요소로 갖는다.

하지만 첫번째로 다른점은 key에 string이 아닌 다른 어떠한 값이나 객체도 가능하다.

(객체의 키에는 객체를 할당할수없고, number를 넣더라도 string으로 타입캐스팅된다.)

조금 특이하게 NaN을 키로 지정할때, NaN !== NaN이지만, Map의 키에서는 동일하다고 간주한다.

나머지 값들은 === 연산자의 결과를 따른다.

두번째는 Map 객체는 iterable객체이다. 객체도 iterable을 구현하거나 비슷한 동작을 하게할수있지만, 번거롭다.

세번째는 순서보장이다. object는 브라우저마다 순서가 다를수있고, 삽입순으로 순서의 정렬이 보장되지않는다.

네번째는 속성의 숫자. size혹은 length의 판별이다. map은 size라는 프로퍼티를 제공한다. 객체는 직접 판별해야한다.

다섯번째는 객체는 프로토타입을 가져서, 키의 충돌위험성이 있다.

여섯번째로 키를 추가하거나 제거할때의 성능은 Map이 더 좋다.

# Set

es6에서 map뿐만아니라 Set 객체도 추가되었다.

map이 object와 비슷하다면, set은 array와 비슷하지다.

new Set(iterable);

map처럼 아무값이나 넣을수있고, 순서보장을 해준다. NaN을 map과 동일하게 처리한다. 유사한 점이 많다.

다른점은 Set 내의 값은 유일하다. 동일한 값을 넣으면 무시된다.

Set을 이용해서 집합연산을 구현한 예제 (Array.from은 생략가능)

// 합집합
const getCombinedSet = (list1, list2) => Array.from(new Set([...list1, ...list2]));

// 차집합
const getDifferenceSet = (list1, list2) => {
  const set2 = new Set(list2);
  return Array.from(new Set(list1.filter(x => !set2.has(x))));
};

// 교집합
const getIntersectionSet = (list1, list2) => {
  const set2 = new Set(list2);
  return Array.from(new Set(list1.filter(x => set2.has(x))));
};

Map이나 Set모두 iterable객체이므로 spread operator를 사용할수있다.

즉,

[...someMap, ...someSet]

이런 코드가 가능.


# 이터러블, 이터레이터 (Iterable, Iterator Protocol)

직역하면 반복가능한(객체), 반복자 규약이다.

즉, 반복에 대한 내용이다.

iterable하다는 것은 객체가 @@iterator 메소드를 구현했다는 것이고, Symbol.iterator 속성(함수)을 가져야한다는 것이다.

# Iterator Protocol

어떤 객체가 next() 메소드를 갖고 있고, (프로토타입이 갖고 있더라도)

next 메소드는 done, value라는 속성을 가진 객체를 리턴하면 그 객체는 iterator라고 할 수 있다.

done은 생긴것처럼 마지막 반복을 마쳤다면 true, 아니면 false이다.

value는 iterator로부터 반환되는 값이다. done이 true일경우 undefined.

const arr = [1, 2, 3];
const iterator = arr[Symbol.iterator]();
iterator.next(); // {value: 1, done: false}
iterator.next(); // {value: 2, done: false}
iterator.next(); // {value: 3, done: false}
iterator.next(); // {value: undefined, done: true}

# Iterable 객체

String, Array, TypedArray, Map, Set 은 내장 iterable 객체이다.

커스텀 iterable 객체의 구현은 간단히 [Symbol.iterator] 만 구현하면 됩니다.

const obj = { a: 1, b: 2, c: 3 };

obj[Symbol.iterator] = function() {
  const keys = Object.keys(obj);
  return {
    index: -1,
    next() {
      this.index++;
      return { value: obj[keys[this.index]], done: this.index >= keys.length };
    }
  };
}

for(const v of obj) {
  console.log(v);
}

iterable 구현을 위한 예시일뿐이다..

실제로 for of 에서 객체를 쓰고싶다면 Object.entries() 메소드를 사용하도록하자.

for(const [key, value] of Object.entries(obj)) {
  // ...some code
}

# 제너레이터 객체 (Generator)

제너레이터 객체는 제너레이터 함수(function*)가 반환하는 객체이다.

iterable, iterator protocol을 따른다.

따라서 제너레이터를 통해서도 iterable 객체를 구현할 수 있다. (는 아래에서..)

# 제너레이터 함수

제너레이터 함수는 호출해도 즉시 실행되지않고 iterator객체를 반환한다.

iterator 객체의 next메소드를 호출하면 yield를 만날때까지 실행되다가 멈춘다. 이걸 반복한다.

yield*을 만나면 다른 Generator 함수가 위임된다.

# iterable 객체 구현

const obj = {};
obj[Symbol.iterator] = function* () {
  yield 1;
  yield 2;
  yield 3;
};
[...obj]; // [1, 2, 3]

const iterator = obj[Symbol.iterator]();
iterator.next(); // {value: 1, done: false}
const generatorObj = function* () {
  yield 1;
  yield 2;
  yield 3;
}();
[...generatorObj]; // [1, 2, 3]

이렇게 만들어진 iterable 객체는 Array.from() 메소드로 쓰거나,

Map, Set 등에 활용할 수 있습니다.


# template-literals

백틱(`) - 숫자 1 왼편에 있는 특수문자

자바스크립트에서 백틱내에 작성한 문자열들은

표현식(expression)이 포함될 수 있습니다.

`string` //string

const boseok = 'Boseok123';
`string ${boseok} end` //string Boseok123 end

이런식으로 변수를 끼워넣을수도 있고,

const boseok = 'boseok';

`some ${boseok.toUpperCase()} end` //string BOSEOK end

이런식으로 메소드 사용도 가능합니다.

표현식이라면 뭐든지 넣을 수 있습니다.

개행도 가능합니다.

'boseok1\n'+
'boseok2'

`boseok1
boseok2`

# Tagged Templates

태그를 사용하면 템플릿 리터럴을 함수로 파싱 할 수 있습니다.

const var1 = 'some var1';
const var2 = 'some var2';
function someTag(strings, ...params) {
  //strings => ['some ', ' is ', ' end']
  //params => [var1, var2]
  return 'something';
}
const someOutput = someTag`some ${var1} is ${var2} end`;
console.log(someOutput); //something

위의 예제처럼 파라미터로 문자열과 표현식이 넘어옵니다.

함수를 선언해두고 특이한 방식으로 호출하고 있네요.

react styled-component에서 tagged template을 사용하기때문에,

react개발자라면 알아두는게 좋습니다.