#1 기존과 달라진 ES6에서의 리스트 순회 ( for of, for i++)
//기존 리스트 순회
const list = [1, 2, 3];
for (var i = 0; i< list.length; i++) {
console.log(list[i]); // 1 2 3
}
//기존 문자배열 순회
const str = 'abc';
for (var i = 0; i< str.length; i++){
console.log(str[i]); // a b c
}
//바뀐 리스트 순회
for (const a of list) {
console.log(a); // 1 2 3
}
//바뀐 문자배열 순회
for (const a of str) {
console.log(a); // a b c
}
#2 Array, Set, Map을 통해 알아보는 이터러블/이터레이터 프로토콜
Array, Set, Map을 통해 알아보기
console.log('Arr -----------');
const arr = [1, 2, 3];
for (const a of arr) console.log(a); //1 2 3
// arr[0] ~ arr[2]를 통해 값을 조회 가능
console.log('Set -----------');
const set = new Set([1, 2, 3]);
for (const a of set) console.log(a); // 1 2 3
// set[0] ~ set[2]를 통해 값을 조회 불가능
console.log('Map -----------');
const map = new Map([['a', 1], ['b', 2], ['c', 3]]);
for (const a of map) console.log(a); // ['a', 1] ['b', 2] ['c', 3]
// map[0] ~ map[2]를 통해 값을 조회 불가능
set, map에서 set[x], map[x]로 값을 조회 못하는데, arr처럼 숫자로 된 키와 매핑된 값들을 순회하면서 동작하는 방식이 아님을 알 수 있다. 그런데도 for...of문을 통해 값이 순회하며 조회됨 을 볼 수 있는데, 이는 for...of문이 다른 방식으로 동작함을 확인할 수 있다
이터러블/이터레이터 프로토콜
이터러블 프로토콜은 ES6에서 도입된 것으로 순회(반복) 가능한 객체를 나나태는 프로토콜이라 할 수 있다.
for...of 반복문, ...전개 연산자, 구조 분해 등과 같이 함께 동작 할 수 있도록한 프로토콜이다. 즉, 이터러블 이여야만 이러한 동작이 가능하다.
-이터러블: 이터레이터를 리턴하는 [Symbol.iterator]()를 가진 값
-이터레이터: { value, done } 객체를 리턴하는 next()를 가진 값
-이터러블/이터레이터 프로토콜: 이터러블을 for...of, 전개 연산자 등과 함께 동작하도록한 규약
const arr = [1, 2, 3];
for(const n of arr) {
console.log(n);
}
// 1 2 3
console.log(...arr);
// 1 2 3
const [first, ...remain] = arr;
console.log(first, remain);
// 1, [2, 3]
위에서 for...of 순회가 가능한 이유는 이터러블이기 때문인데 아래에서 더 확인해보자.
console.dir(arr);
/*
▼Array(3)
▼__proto__: Array(0)
...
▶ Symbol(Symbol.iterator): f values()
...
*/
Array의 내부에서 Symbol(Symbol.iterator): f values()를 확인할 수 있는데, Array에는 Symbol(Symbol.iterator)이라는 Key를 가진 함수가 존재한다는 것을 알 수 있고, 앞서 설명한 이터레이터를 반환하는 Symbol.iterator이라는 키값의 메소드를 가진 객체에 부합하는 것을 볼수 있다.
위의 코드를 아래와 같이 한번 해보자.
const arr = [1, 2, 3];
arr[Symbol.iterator] = null;
for(const n of arr) {
console.log(n);
}
// Uncaught TypeError: arr is not iterable
console.log(...arr);
arr[Symbol.iterator] = null; 을 통해 이제 더이상 배열 arr은 이터러블이 아니게 되었다. 그래서 for...of에서 arr은 이터러블이 아니라는 오류를 만나게 되었고, 전개 연산자의 경우도 마찬가지다.
이제 이터레이터를 확인해보자.
arr[Symbol.iterator]은 함수이므로, arr[Symbol.iterator]()를 한다면 반환되는 것은 이터레이터가 될 것 이다.
const arrIter = arr[Symbol.iterator]();
console.log(arrIter); // Array Iterator {}
위 코드를 통해 반환된 것이 이터레이터 객체인 것을 확인했다.
이터레이터는 { value, done } 객체를 반환하는 next() 메소드를 가진 객체라고 했었는데 next() 메소드를 확인해보자.
console.log(arrIter.next()); // {value: 1, done: false}
console.log(arrIter.next()); // {value: 2, done: false}
console.log(arrIter.next()); // {value: 3, done: false}
console.log(arrIter.next()); // {value: undefined, done: true}
보는 것과 같이 { value, done } 객체가 반환 된 것을 볼수 있는데, value값이 있을 때는 done이 false값을 가지고, 이제 순회할 것 이 없는 상황에는 done이 true값을 가진다.
또 다른 예제를 통해 알아보자.
const arrIter2 = arr[iterator]();
arrIter2.next();
for(const v of arrIter2){
console.log(v);
}
// 2 3
반복문 전에 next()를 한번 해서 첫번째 값 1은 출력이 안된 것을 확인 할 수 있다.
마지막으로 map에서는 다음과 같이 순회가 가능하다.
const map = new Map([['a', 1], ['b', 2], ['c', 3]]);
for (const a of map.keys()) console.log(a); // a b c
for (const a of map.values()) console.log(a); // 1 2 3
for (const a of map.entries()) console.log(a); // ['a', 1] ['b', 2] ['c', 3]
※map 함수 .keys(): key값 출력 .values(): value값 출력 .entries(): key, value값 출력 |
#3 사용자 정의 이터러블을 통해 알아보기
사용자 정의 이터러블
이터러블 프로토콜을 따라서 순회 동작을 사용자 정의할 수 있다는 점이 이터러블을 활용하는데 있어 중요한 의의를 가진다.
const iterable = {
[Symbol.iterator]() {
let i = 3;
return {
next() {
return i === 0 ? { value: undefined, done: true } : { value: i--, done: false };
}, // ① next()함수 구현
[Symbol.iterator]() { return this; }
// ② Symbol.iterator을 실행했을때 자기자신을 리턴하도록 하기
}
}
};
let iter2 = iterable[Symbol.iterator](); // ②가 없으면 실행 불가
console.log(iter2[Symbol.iterator]() == iter2); // true
iter2.next();
for (const a of iter2) console.log(a); // 2 3
'Web[웹] > ES6+ 함수형 언어' 카테고리의 다른 글
[JS: ES6+] 제너레이터/이터레이터 프로토콜로 구현하는 지연 평가 (1) (0) | 2019.10.08 |
---|---|
[JS: ES6+] 장바구니 예제로 코드를 줄이고 HTML로 표현해보기 (0) | 2019.10.07 |
[JS: ES6+] 코드를 값으로 다루어 표현력 높이기 (go, pipe) (0) | 2019.10.04 |
[JS: ES6+] 이터러블 프로토콜을 따른 map, filter, reduce (0) | 2019.10.02 |
[JS: ES6+] 제너레이터와 이터레이터 (0) | 2019.09.30 |