선언

generator function을 통해 반환된 객체이다. Iterable protocol을 만족하면서 Iterator protocol을 만족하는 객체이다.

const generator = function*() {
 	yield 1;
}
console.dir(generator()); // generator

generator의 특징을알기 위해서는 Iterable protocol과 Iterator protocol에 대해 알아야 한다.

Iterable protocol

Iterable protocol은 Symbol.iterator를 키로 갖는 인자가 없고 iterator객체를 반환하는 함수여야 한다.

Iterator protocol

아래의 사항들을 만족한다면 Iterator 객체이다.

Iterable protocoliterator protocol을 만족하는 객체를 만든다면 for...of나 spread 연산자와 같은 기능을 사용할 수 있다.

const object = {
 	[Symbol.iterator]() {
     	return {
          v: [1,2,3],
          next() {
            return {
              done: this.v.length === 0,
              value: this.v.shift(),
            }
          }
        }
    }
}

for (const iterator of object) {
  console.log(iterator)
}  // 1,2,3
console.log(...object); // 1 2 3
console.log(new Array(...object)) // [1,2,3]

기본적인 메소드

const gen = function*() {
  let i = 0;
  while(true){
    let v;
    v = yield i++;
    console.log(v)
  }
}();
console.log(gen.next(4));  // {value: 0, done: false}
console.log(gen.next(5));
// 4,
// {value: 1, done: false}

const gen = function*(){
  yield 1;
  try {
    yield 2;
    yield 3;
  } finally {
    yield 'clean up';
  }
}
const gen1 = gen();
console.log(gen1.next()); // {value: 1, done: false}
console.log(gen1.return('early return')); // {value: 'early return', done: true');
console.log(gen1.next()); // {value: undefined, done: false}

const gen2 = gen();
console.log(gen2.next()); // {value: 1, done: false}
console.log(gen2.next()); // {value: 2, done: false}
console.log(gen2.return('early return')); // {value: 'clean up', done:false}
console.log(gen2.next()); // {value: 'early return', done:true}
console.log(gen2.next()); // {value: 'undefined', done:true}

try...catch블록에서 return()이 실행된다면 finally 문의 yield가 실행되고 done이 true가 된다.

function* gen4() {
  while (true) {
    try {
      yield 42;
    } catch (e) {
      console.log('Error caught!');
    }
  }
}

const g = gen4();
g.next();
// { value: 42, done: false }
g.throw(new Error('Something went wrong'));
// "Error caught!"
// { value: 42, done: false }