오늘날 generator function을 사용하는 사람들은 매우 적다. 현재 상태에 따라, 결과가 달라진다라는 것도 요즘 패러다임에는 맞지 않는 방식이니까 말이다. 하지만, 이번에 Stage 3 Draft / December 12, 2023 스펙에 "Iterator Helpers"가 등장한 것은 꽤나 흥미로운 일이다.
언젠가 iterator에 대해서 다루면서, 가장 간단하게 iterator를 생성하는 방법으로 generator function을 소개하였다.
function *test () {
yield 1;
yield 2;
yield 3;
}
let iter = test();
const arr = [...iter];
console.log('arr', arr);
iter = test();
for(const item of iter) {
console.log('item', item);
}
iterator는 펼침연산을 수행할 수 있고, for of를 이용하여 순회 할 수 있다. 하지만 무엇인가 부족했다. iterator 자체로는 map을 사용할 수 도 없고, filter를 사용할 수 없었다.
그것이 바로 Iterator helpers인 것이다.
function *test () {
yield 1;
yield 2;
yield 3;
}
[...test().map(v => v * 2).filter(v => v % 3)]
map과 filter를 사용하여, 새로운 iterator를 받을 수 있게 되었다. 그 뿐만이 아니다.
[...test().flatMap(v => test()).map(v => v * 2).filter(v => v % 3)]
당연하게도, flatMap이 사용 가능하다!
위에서는 펼짐 연산자를 이용하여, 배열로 형변환을 해주었지만?
test().toArray()
이처럼 어떤 형태로, 컬렉션을 치환할지도 처리가 가능해지기 때문에, 추후에는 문자열과 같인 [Symbol.iterator]를 같는 데이터들도 추가적으로 지원할 수도 있고, 2차원 배열의 경우, Map형태로 치환 하는 것도 당연 가능하게 될 것 같다.
iterator는 게으르다.
자 이것이 무슨말일까? iterator는 배열이 아니라는 것에 일단 동의를 해야한다.
배열의 map, filter, forEach는 순회메서드라고 부를만하다. 각 함수들을 실행할 때 마다, 배열을 수회하니까 말이다. 하지만 iterator(반복자)는 자체가 순회인 것이다.
iterator는 next() | yield를 호출 되는 순간 요청받은 값을 map, filter, forEach에 전달해주는 방식을 취한다.
test().map(v => {
console.log('iterator map called')
return v * 2
}).filter(v => {
console.log('iterator filter called')
return v % 3
})
.toArray().map(v => {
console.log('array map called')
return v * 2
}).filter(v => {
console.log('array filter called')
return v % 3
})
자 위의 콘솔을 잠깐 보면 확인 가능 할 것 이다.
iterator -> map(value) -> filter(value)를 각각의 value로 호출하고 있다. 하지만...
Array -> map(Array) -> map(Array)를 배열의 단위로 호출 하고 있다.
게으름의 미학
자 간단하게, 특정 연산(map)을 하고, filter을 하고 최초의 최초의 세개만 갖고 싶다고 하자. 1000개의 데이터로 말이다.
const iter = arr[Symbol.iterator]()
iter
.map((v, i) => {
console.log('iter map called')
return i
})
.filter(v => {
console.log('iter filter called')
return v % 3
})
.take(3).toArray()
arr
.map((v, i) => {
console.log('arr map called')
return i
})
.filter(v => {
console.log('arr filter called')
return v % 3
})
.slice(0, 3)
iterator의 경우, map 5번, filter 5번 만에 최초의 3개를 찾아낼 수 있었지만,
배열로 처리하는 경우, map 1000번, filter 1000번 만에, 최초의 3개를 찾아 낼 수 있었다.
이걸 평가지연이라고 한다.
댓글
댓글 쓰기