← 글 목록

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 등 별 경로.