Iterable이란 ?
자바스크립트에서 iterable
이란 반복이 가능함을 의미한다.
반복이 가능한 요소는 무엇이 있을까?
배열
, Map
, Set
등 모두 iterable
한 요소이다.
이러한 요소들이 iterable 한 것은 Iteration Protocol
을 따르기 때문이다.
Iteration Protocol 을 따름으로써 for ... of
구문이나 spread
문법 등을 사용할 수 있게 된다.
Iteration Protocol이란?
Object를 iterable하도록 만드는 표준방법을 제시하는 일종의 규약이다.
이 프로토콜을 따라 iterator을 구현할 수 있다.
Object가 iterable 하기 위해서는 @@iterator
메소드를 가지고 있어야 한다.
이는 Object가 [Symbol.iterator]
라는 속성을 가지고 있어야 한다는 의미이다.
Iterator의 조건
또한 어떠한 Object가 iterator가 되기 위해서는 다음의 조건을 만족해야한다.
{
...,
next() {
return {
value: any,
done: boolean,
}
}
}
value
와 done
을 반환하는 next
라는 메서드를 가지고 있어야 한다.
이 때,
value는 iterator가 반환하는 어떠한 값을 의미한다.
done은 iterator가 종료되었는가를 의미하는 boolean 값이다.
Map의 iteration
Map을 통해 iterator를 확인해보자.
const myMap = new Map();
myMap.add('a', 1);
myMap.add('b', 2);
myMap.add('c', 3);
myMap.add('d', 4);
const iter = myMap[Symbol.iterator](); // Map Iterator
iter
은 iteration protocol에 의해 next
라는 메서드를 가지고 있을 것이다.
iter.next(); // { value: [a, 1], done: false }
iter.next(); // { value: [b, 2], done: false }
iter.next(); // { value: [c, 3], done: false }
iter.next(); // { value: [d, 4], done: false }
iter.next(); // { value: undefined, done: true }
for (const [key, val] of myMap) {
console.log(key, val); // a 1, b 2, c 3, d 4
}
console.log([...myMap]); // [[a,1], [b,2], [c,3], [d,4]]
커스텀 iterator
앞에서 언급한 내용을 통해 커스텀 iterator을 만들어보자.
다음과 같은 foo 객체가 있을 때, 값의 타입이 배열인 것만 출력하고 싶을 때의 iterator을 만들어보자.
const foo = {
bar: [1,2,3,4,5],
toz: 'hello',
kor: [5,6,7,8,9],
mzp: () => 'func!',
};
next 함수 정의해서 구현
function getIterator() {
let valueIdx = 0;
const fooValues = Object.values(foo);
const iter = {
next() {
while(!Array.isArray(fooValues[valueIdx])){
if (++valueIdx >= fooValues.length) {
return {
value: undefined,
done: true,
}
}
}
return {
value: fooValues[valueIdx++],
done: false,
};
},
};
return iter;
}
const iter = getIterator();
iter.next(); // { value: [1,2,3,4,5], done: false }
iter.next(); // { value: [5,6,7,8,9], done: false }
iter.next(); // { value: undefined, done: true }
generator function 구현
// 1번 방법
foo[Symbol.iterator] = function* () {
for (let key of Object.values(this)) {
if (Array.isArray(key)) yield key;
}
}
for (let val of foo) {
console.log(val); // [1,2,3,4,5], [5,6,7,8,9];
}
// 2번 방법
function *getIterator() {
for (let key of Object.values(foo)) {
if (Array.isArray(key)) yield key;
}
}
const iter = getIterator();
for (let val of iter()) {
console.log(val); // [1,2,3,4,5], [5,6,7,8,9];
}
next() 함수를 정의할 경우 인덱스 같이 현재 상태에 대한 정보를 가지고 있어야하는 반면
생성자 함수 를 사용하면 훨씬 간단하게 구현할 수 있다.
'유연해지기 > Javascript' 카테고리의 다른 글
JavaScript Set 내 맘대로 구현하기 (1) | 2022.11.30 |
---|---|
Vanilla Javascript로 간단한 SPA 라우터 구현해보기 (4) | 2022.05.13 |
[Javascript] Promise 예제 풀어보기 (0) | 2021.09.12 |
[Javascript] 자바스크립트 Map 정렬하기 (0) | 2021.05.03 |