자바스크립트

Section 10. 자바스크립트 제너레이터

포칼이 2023. 4. 7. 12:27

제너레이터의 특징은 다음과 같다

  • 함수 내 코드들을 모두 실행하지 않고 외부 호출자에게 제어권을 양도한다. - "계속할까요?"
  • 이터러블과 이터레이터를 보다 간결하게 구현 가능하다.
function* genFunction () {
  console.log('하나를 반환합니다.');
  yield '하나';

  console.log('둘을 반환합니다.');
  yield '둘';

  console.log('셋을 반환합니다.');
  yield '셋';
}

const genFunc = genFunction();

// 반복 수행해 볼 것
// 💡 아래의 코드가 블록의 코드에 대한 제어권을 가짐
console.log( genFunc.next() );
//하나를 반환합니다.
//{value: '하나', done: false}

 

I. 기본 사용법

1. 제너레이터 함수 / 메서드 선언

function 다음 또는 메서드명 앞에 * 를 붙인다. 띄어쓰기 위치는 무관하다.

// 함수 선언
function* genFunc1 () {
  yield 'genFunc1';
}
// 값으로 대입
const genFunc2 = function* () {
  yield 'genFunc2';
}
// 객체의 메서드
const obj = {
  * genFunc3 () {
    yield 'genFunc3';
  }
}
// 클래스의 메서드
class MyClass {
  * genFunc4 () {
    yield 'genFunc4';
  }
}

이런식으로 선언을 하고 출력하면 다음과 같다

// 테스트
console.log(
  genFunc1().next().value,
  genFunc2().next().value,
  obj.genFunc3().next().value,
  new MyClass().genFunc4().next().value,
); //genFunc1 genFunc2 genFunc3 genFunc4

*yield?

일반적인 함수에서는 return문으로 return값을 써주지만 제너레이터에서는 return대신 yield를 쓴다. 

yield 'genFunc1'; 하면 genFunc1을 리턴값으로 넘기겠다는 뜻이 된다.

 

2. 제너레이터 객체

  • 제너레이터 함수의 결과값으로 반환된다.
  • 이터레이터이자 이터러블이다.
function* genFunction () {
  yield 1;
  yield 2;
  yield 3;
  yield 4;
  yield 5;
}

let genObj = genFunction();

제너레이터 함수 genFunction의 결과값인 genObj가 있다. genObj는 제너레이터 객체이다.

제너레이터 객체는 next도 있고 심볼 이터레이터도 있다. 즉, 제너레이터 객체는 이터러블과 이터레이터의 기능을 기반으로 만들어져 있다는 것을 알 수 있다. 

 

순회 후에는 재생성이 필요하다.

console.log([...genObj]); //[]

따라서 이터러블로서는 바로 호출이 적합하다.

console.log([...genFunction()]); //[1, 2, 3, 4, 5]

 

다시한번 정리하자면 다음과 같다

  • next 메서드를 실행하면 다음 yield까지 실행 후 중지
  • yield의 값을 value로 반환
  • 끝까지 실행 후 done : true

II. 이터러블과 이터레이터 대체하기

이터러블 정리에서 했었던 주사위 굴리는 예제를 제너레이터를 사용하여 엄청 간단하게 만들 수 있다.

 

주사위를 열 번 굴리는 제너레이터

function* diceTenTimes () {
  let count = 0;
  const maxCount = 10;

  while (count++ < maxCount) {
    yield Math.ceil(Math.random() * 6);
  }
}
// 이터러블
console.log(
  [...diceTenTimes()]
); //[1, 5, 4, 1, 2, 1, 4, 3, 5, 3]
// 이터레이터 - 객체로 반환 뒤 사용
// ⚠️ 다시 순회시 재생성 필요
let diceGenObj = diceTenTimes();

for (let i = 0; i < 12; i++) {
  console.log(diceGenObj.next());
}