[functional JS ES6+] generator와 iterator

작성:    

업데이트:

카테고리:

태그: , ,

본 포스트는 인프런의 함수형 프로그래밍과 JavaScript ES6+ 강의(링크)를 듣고 정리한 내용입니다.


generator

  • iterator이자, iterable을 생성(return)하는 함수
  • iter[Symbol.iterator]() == iter, 즉 자기 자신을 return하는 well-formed iterator
function *gen() {
  yield 1;
  yield 2;
  yield 3;
  return 100;
}

let iter = gen();
log(iter.next()); // {value: 1, done: false}
log(iter.next()); // {value: 2, done: false}
log(iter.next()); // {value: 3, done: false}
log(iter.next()); // {value: return, done: true}

for (const a of gen()) log(a); // 1 \n 2 \n 3
  • 일반 함수 앞에 ‘*’ 표시를 붙여 만든다.
  • iterator이므로 next() method와 for of 문을 통한 순회도 가능
  • yield로 각 단계를 표시하고, return값은 done: true에 나오는 값


yield는 문장도 가능

yield 1;
if (false) yield 2;
yield 3;

이는 곧 어떠한 값도 순회할 수 있는 객체로 만들 수 있다는 말


generator의 활용

홀수 generator: odds

홀수만 뽑는 generator odds를 만든다

function *adds(l) {
  for (let i=0; i<l; i++) {
    if (i % 2) yield i;
  }
}
let iter2 = odds(10);
log(iter2.next()); // {value: 1, done: false}
log(iter2.next()); // {value: 3, done: false}
log(iter2.next()); // {value: 5, done: false}
log(iter2.next()); // {value: 7, done: false}
log(iter2.next()); // {value: 9, done: false}
log(iter2.next()); // {value: undefined, done: true}
log(iter2.next()); // {value: undefined, done: true}


무한수열 generator: infinity

function *infinity(i = 0) {
  while (true) yield i++;
}

let iter3 = infinity();
iter3.next(); // {value: 1, done: false}
iter3.next(); // {value: 2, done: false}
iter3.next(); // {value: 3, done: false}
iter3.next(); // {value: 4, done: false}
  • iterator의 next를 평가할 때까지만 동작하므로 while문에 따른 오류는 없다.


여러 generator의 결합

function *infinity(i = 0) {
  while (true) yield i++;
}

function *odds(l) {
  for (const a of infinity(1)) {
    if (a % 2) yield a;
    if (a == l) return;
  }
}

let iter2 = odds(10);
log(iter2.next()); // {value: 1, done: false}
log(iter2.next()); // {value: 3, done: false}
...
log(iter2.next()); // {value: 9, done: false}
log(iter2.next()); // {value: undefined, done: true}

/////////////////////////////////////////////////////////////////

function *limit(l, iter) {
  for (const a of iter) {
    yield a;
    if (a == l) return;
  }
}

let iter4 = limit(4, [1, 2, 3, 4, 5, 6]);
log(iter4.next()); // {value: 1, done: false}
log(iter4.next()); // {value: 2, done: false}
log(iter4.next()); // {value: 3, done: false}
log(iter4.next()); // {value: 4, done: false}
log(iter4.next()); // {value: undefined, done: true}

댓글남기기