1. 제너레이터
1-1. 예제 코드
  function* gen() {
    yield 1;
    if (false) yield 2;
    yield 3;
  }
  let iter = gen(); 
  log(iter[Symbol.iterator]() == iter); 
  log(iter.next());
  log(iter.next());
  log(iter.next());
  log(iter.next());
  for (const a of gen()) log(a);
  console.clear();
true
{value: 1, done: false}
{value: 3, done: false}
{value: undefined, done: false}
{value: undefined, done: false}
1
3
- 제너레이터를 만들 때 함수 명 앞에 *을 붙여준다.
1-2 홀수를 반환하는 이터레이터 만들기
 function* infinity(i = 0) {
    while (true) yield i++;
  }
  function* limit(l, iter) {
    for (const a of iter) {
      yield a;
      if (a == l) return;
    }
  }
  function* odds(l) {
    for (const a of limit(l, infinity(1))) {
      if (a % 2) yield a;
    }
  }
  let iter2 = odds(10);
  log(iter2.next());
  log(iter2.next());
  log(iter2.next());
  log(iter2.next());
  log(iter2.next());
  log(iter2.next());
  log(iter2.next());
  for (const a of odds(40)) log(a);
  console.clear();
- 홀수를 출력하는 odds 제너레이터는 limit, infinity 제너레이터를 합쳐서 만든 제너레이터다.
- limit에서 iter라는 인자는 infinity 제너레이터를 받고 있음. for.. of문에서 값이 l과 같아질 때 까지 실행된다.
- infinity는 i부터 값이 무한으로 증가한다. 이터레이터의 next를 평가할 때 까지만 작동해 프로그램이 멈추거나 하는 현상이 일어나지는 않는다.
1-3. for of, 전개 연산자, 구조 분해, 나머지 연산자 (이터레이터 프로토콜)
  log(...odds(10));
  log([...odds(10), ...odds(20)]); 
  const [head, ...tail] = odds(5); 
  log(head);
  log(tail);
  const [a, b, ...rest] = odds(10);
  log(a);
  log(b);
  log(rest);