[javascript] ES6 순회와 이터러블/이터레이터 프로토콜
1. 이터러블과 함수형 프로그래밍
최근 javascript 함수형 프로그래밍
을 공부하면서 알게 된 ES6 순회와 이터러블/이터레이터 프로토콜의 관계에 대해 공부하게 되었습니다. 제 생각으로는 함수형 프로그래밍에서 이터러블/이터레이터 프로토콜은 핵심적인 개념이라고 생각합니다. 생각보다 간단한 원리에서 시작한 개념이 함수형 프로그래밍에서 아주 요긴하게 쓰입니다. 본 게시글은 타 블로그 및 MDN에서 참조한 내용으로 작성되었습니다.
2. 이터러블/이터레이터 프로토콜
이터러블/이터레이터 프로토콜은 MDN에서 iteration protocols
라고 칭하고 있습니다. 이터레이터가 무엇인지 알아보기 전에, 이터레이터가 어디에 쓰이고, 왜 쓰이는지 알아보겠습니다.
배열 순회
ES5
에서 for문을 통한 배열 순회는 아래와 같이 작성되었습니다.
const arr = [1, 2, 3, 4, 5];
for(let i = 0; i < arr.length; i++) {
console.log(arr[i]); // 1, 2, 3, 4, 5
}
아래는 변경된 ES6
에서 배열 순회입니다.
const arr = [1, 2, 3, 4, 5];
const str = 'abc';
const mySet = new Set([1, 2, 3, 4, 5]);
for(const a of arr){ // for...of로 리스트 안에 있는 값(a)을 순회한다.
console.log(a); // 1, 2, 3, 4, 5
}
for(const a of str){
console.log(a); // a, b, c
}
for(const a of mySet) {
console.log(a); // 1, 2, 3, 4, 5
}
하지만 기존 ES5
에서 사용되는 순회는 큰 문제점이 있습니다. 바로 for문으로 순회하기 위해 length
라는 속성에 의존
해야 한다는 것입니다. 즉, 순회하고자 한다면 꼭 __proto__
또는 constructor
에서 length
를 프로토타입 기반으로 상속
을 받아야 한다는 점입니다. 아래 코드를 보시면 이해에 도움이 되실 것 같습니다.
const mySet = new Set([1, 2, 3, 4, 5]);
for(let i = 0; i < mySet.keys().length; i++) {
console.log('hello');
}
그리고 mySet.keys()
의 값을 로그로 찍어보면 아래와 같습니다.
SetIterator {1, 2, 3, 4, 5}
0: 1
1: 2
2: 3
3: 4
4: 5
Set
형의 keys()
는 length
프로퍼티를 가지고 있지 않기 때문에 for문에서 아무 로그도 나오지 않게 됩니다. 반환된 SetIterator
는 아래부터 설명하게 될 이터러블
과 이터레이터
와 관련 있습니다.
이터러블
이터레이터를 리턴하는 Symbol.iterator() 라는 메서드를 가진 값
이터러블은 객체의 값을 반복 순회할 수 있는 자격을 가진 객체를 뜻합니다. js에서 객체가 이터러블이 되기 위해서는 해당 객체에 Symbol.iterator
메서드를 가지고 있어야 합니다. 예시 코드를 보여드리겠습니다.
const arr = [1, 2, 3];
arr[Symbol.iterator]; // ƒ values() { [native code] }, >> 메서드
arr[Symbol.iterator](); // Array Iterator {} >> 배열형 이터레이터 객체
Araay
형의 Symbol.iterator()
메서드로 이터레이터를 반환받았기 때문에 Array
는 이터러블 하다 또는 이터러블 프로토콜을 준수했다. 라고 할 수 있습니다.
이터레이터
{ value, done }
객체를 리턴하는next()
라는 메서드를 가진 값
이터러블 객체로부터 [Symbol.iterator]()
메서드를 이용하여 이터레이터를 반환받은 후 이터레이터 객체에 next()
메서드를 통해서 이터러블 객체들의 순회 정보를 확인할 수 있습니다.
const arr = [1, 2, 3];
let iterator = arr[Symbol.iterator](); // 반환받은 이터레이터 객체를 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}
for...of 문
이때 for of
문은 이터러블의 이터레이터를 받아와 next()
를 호출하면서 { value, done }
객체를 받아오고 value
의 값을 사용합니다. 그러다 done
이 true
이면 순회를 종료합니다. 하지만 이미 다양한 오픈소스와 웹 API들, DOM 객체 관련 등 에도 이터러블 프로토콜을 이미 따르고 있기 때문에 해당 프로토콜을 이용해 순회를 하시면 되겠습니다.
const mySet = new Set([1, 2, 3, 4, 5]);
for(const a of mySet) {
console.log(a); // 1, 2, 3, 4, 5
}
const nodeList = document.querySelectorAll('*');
for(const a of nodeList) {
console.log(a);
// {value: html, done: false}
// {value: head, done: false}
// {value: meta, done: false}
// ...
}
const map = new Map([['a', 1], ['b', 2], ['c', 3]]);
for (const a of map.keys()) {
console.log(a);
// a
// b
// c
}
전개 연산자
이터러블 객체의 요소를 전개해줍니다 ...이터러블객체
키워드로 사용합니다.
const a = [1, 2, 3, 4];
console.log(...a);
// 1, 2, 3, 4
3. 사용자 정의 이터러블
새로운 이터러블 객체 만들어 보면서 이터러블에 대해 깊게 알아보겠습니다. 방법은 아래와 같습니다.
● Symbol.iterator() 메서드 구현하기
● 이터레이터의 반환 값을 자기 자신(이터레이터)로 설정
/* 사용자 정의 이터러블 */
const iterable = {
[Symbol.iterator]() {
let i = 3;
return {
next() {
return i == 0 ? { done: true } : { value: i--, done: false };
},
[Symbol.iterator]() {
return this; // 자기 자신을 return 한다.
},
};
},
};
/* 이터러블 객체인지 for...of 문으로 확인하기 */
for (const a of iterable) console.log(a);
// 3
// 2
// 1
let iterator = iterable[Symbol.iterator]();
iterator.next(); // 3
for (const a of iterator) console.log(a);
// 2
// 1
잘 만든 이터러블(well-formed Iterable)이란?
이터레이터를 만들어서 순회를 할 때 잘 동작한다.
이터레이터에게 Symbol.iterator() 메서드는 이터레이터 자기 자신을 반환한다.
'Javascript > ES6' 카테고리의 다른 글
[javascript] ES6 문법 활용 정리 (0) | 2022.06.12 |
---|---|
[javascript] ES6 구조분해 할당 총 정리 (2) | 2021.09.27 |
댓글
이 글 공유하기
다른 글
-
[javascript] ES6 문법 활용 정리
[javascript] ES6 문법 활용 정리
2022.06.12 -
[javascript] ES6 구조분해 할당 총 정리
[javascript] ES6 구조분해 할당 총 정리
2021.09.27