notes
Iterator · Generator — next와 yield
Iterable/Iterator 규약과 Generator. for…of가 도는 이유.
참고: MDN Iteration protocols / Generators, ECMA-262 Iterator
for…of가 도는 이유는 배열이 특별해서가 아니다.
이터러블이 Symbol.iterator로 이터레이터를 내놓고, 이터레이터가 { value, done }을 반복하는 규약이다.
flowchart LR
ITB[Iterable<br/>Symbol.iterator] --> ITR[Iterator]
ITR -->|next| R["{ value, done }"]
R -->|done false| ITR
R -->|done true| END[끝]
const arr = [10, 20];
const it = arr[Symbol.iterator]();
console.log(it.next()); // { value: 10, done: false }
console.log(it.next()); // { value: 20, done: false }
console.log(it.next()); // { value: undefined, done: true }
for (const n of arr) console.log(n);
직접 이터러블을 만들 수 있다.
const range = {
from: 1,
to: 3,
[Symbol.iterator]() {
let cur = this.from;
const last = this.to;
return {
next() {
if (cur <= last) return { value: cur++, done: false };
return { value: undefined, done: true };
},
};
},
};
console.log([...range]); // [1, 2, 3]
Generator
function*는 이터레이터를 찍어 내는 공장이다. yield마다 멈췄다가 next로 이어간다.
function* gen() {
yield 1;
yield 2;
return 3; // done:true의 value (for…of에선 보통 무시)
}
console.log([...gen()]); // [1, 2]
yield*로 다른 이터러블을 위임할 수 있다.
비동기 쪽은 async generator / for await…of로 이어진다.
질문 → 자답
Q. 배열을 다 만들어 두고 도나?
A. 이터레이터는 게으를 수 있다. 제너레이터·스트림이 그 맛이다.
Q. Map/Set/문자열도?
A. 전부 이터러블. 객체 키 순회는 Object.keys 등 별 경로.