[JS] #11 Generator 오브젝트

simoniful·2021년 4월 29일
0

ES6 JS - Basic

목록 보기
11/18
post-thumbnail

Generator 함수

일반 함수는 하나의 값(혹은 0개의 값)만을 반환합니다.
하지만, 제너레이터(generator)를 사용하면 여러 개의 값을 필요에 따라 하나씩 반환(yield)할 수 있습니다. 제너레이터와 이터러블 객체를 함께 사용하면 손쉽게 데이터 스트림을 만들 수 있습니다.

Generator 함수는 기존 함수 선언(표현)과 다르게 function뒤에 *키워드가 붙습니다. 그래서 function* 를 키워드로 사용합니다. 제너레이터 함수 형태는 일반 함수 형태처럼 function* 선언문, function* 표현식, GeneratorFunction이 있습니다.

// 선언문
function* sports(one){}
// 표현식
const book = function*(one){};
// GeneratorFunction
const music = Object.getPrototypeOf(function* (){}).constructor;
const gen = new music();

function* 선언문

일반 함수 선언문과 동일하게 function* 뒤에 함수명을 작성합니다. 제너레이터 함수를 호출하면 함수 블록({ }) 을 실행한 결과값이 아니라 Generator 오브젝트를 생성하여 반환합니다. 여기서 Generator 오브젝트는 iterator 오브젝트로 next()를 통해 결과값을 받을 수 있습니다.

function* sports(one, two) { yield one + two; }
console.log(typeof sports);
const obj = sports(1, 2);
console.log(typeof obj);
console.log(obj.next());
// function
// object
// {value: 3, done: false}
  1. console.log(typeof sports);
    ⇒ 제너레이터 함수의 타입은 function 입니다.
  2. const obj = sports(1, 2);
    ⇒ sports 함수를 호출하면 Generator Object를 생성하여 반환합니다. 이 반환하는 시점에서 함수의 블럭 안 코드를 실행하지는 않습니다. 그리고 sports 함수를 호출할 때 보낸 파라미터는 오브젝트에 설정되어 있습니다.
  3. new 연산자를 사용할 수 없는데, 이는 단일 함수로 사용하겠다는 의미입니다.
  4. typeof obj
    ⇒ Generator 오브젝트의 타입은 object입니다.
  5. obj.next()
    ⇒ Generator 오브젝트가 iterator 오브젝트이기에 next() 함수를 호출할 수 있고 이 때 코드가 실행됩니다.

정리

  • 제너레이터 함수를 호출하면 함수 블록 실행을 하지 않고 Generator 오브젝트를 생성 및 반환.
  • Generator 오브젝트는 Iterator 오브젝트이다
  • new 연산자를 사용할 수 없다.
    ⇒ Generator 타입의 prototype에 메소드를 연결해 인스턴스를 만드는 것이 목적이 아니다.

function* 표현식

함수표현식과 표기법은 동일합니다. function* 다음에 함수 이름을 작성하는것은 필수가 아니며 만약 작성하게 된다면 재귀적 호출(recursive call)에 사용할 수 있습니다.

하지만, 일반적으로는 함수 이름을 작성하지 않고 좌측에 설정되는 변수명이 함수 이름이 됩니다. 일반 함수 표현식과 마찬가지로 선언형태만 다를 뿐 function* 선언문과 동일합니다.

const sports = function* (one) { yield one;};
const obj = sports(100);
console.log(obj.next());
// {value: 100, done:false}
  1. const sports = function* (one){ yield one;};
    ⇒ 표현식 형태의 제너레이터 함수입니다.
  2. sports가 함수 이름이 되며, 일반적으로 * 다음에 함수 이름을 사용하지 않습니다.

GeneratorFunction

GeneratorFunction.constructor를 사용해 제너레이터 함수를 생성합니다. 주의할 점은 제너레이터 오브젝트가 아닌 함수를 생성한다는 점입니다.

파라미터를 문자열로 작성하고 마지막 파라미터가 함수 코드가 되고 앞은 파라미터 이름이 됩니다. Generator에는 생성자가 없기 때문에 GeneratorFunction의 constructor를 사용하여 Generator의 constructor를 구하는 사전작업을 먼저 해줘야 합니다.

제너레이터 함수 구조

const gen = function*(){}

  1. 제너레이터 함수 gen의 scope를 전개하면 prototype이 있습니다. 하지만, prototype을 펼치면 constructor도 없고 next()나 throw()와 같은 메소드 역시 연결되어 있지 않습니다.
  2. 대신 __proto__가 있고 이 안에 constructor와 next(), throw() 등이 있는데 __proto__안에 있다는 것은 다른 오브젝트의 prototype에 연결된 프로퍼티를 인스턴스 개념으로 생성하여 첨부했다고 할 수 있습니다.
  3. constructor를 살펴보면 해당 __proto__는 GeneratorFunction의 constructor가 첨부된 것이라는것을 확인할 수 있습니다.
const fn = new Function("one", "return one");
console.log(fn(100));
const create = Object.getPrototypeOf(function*(){}).constructor;
console.log(create);
const sports = new create("one", "yield one");
const obj = sports(100);
console.log(obj.next());
// 100
// {value: 100, done: false}
  1. const create = Object.getPrototypeOf(function*(){}).constructor;
    ⇒ 제너레이터 함수를 생성하는 constructor(생성자)를 할당합니다. 이렇게 constructor가 할당되기에 이제 new 연산자를 통해 생성자 함수를 호출할 수 있습니다.
  2. console.log(create);
    ⇒ function GeneratorFunction(){[native code]}을 출력하는데, create에 할당된 생성자가 Generator가 아닌 GeneratorFunction의 생성자이기 때문입니다.
  3. const sports = new create("one", "yield one");
    ⇒ GeneratorFunction을7 사용해 제너레이터 함수를 생성 후 sports 변수에 할당합니다.
    ⇒ 파라미터로 sports에서 사용할 파라미터와 함수 코드를 작성합니다 .
    • one: 파라미터 이름
    • yield one: 함수 코드
  4. console.log(typeof sports);
    ⇒ new 연산자를 사용했지만 인스턴스가 아니기에 object가 아닌 function 입니다.
    ⇒ function이라는 의미는 function* sports()로 제너레이터 함수를 선언한 것을 뜻하며, 지금까지 제너레이터 함수를 선언하는 처리를 했다는 말과 같습니다.
  5. const obj = sports(100);
    ⇒ sports에 작성된 함수코드를 호출하며 파라미터 이름인 one에 100을 작성합니다.
    ⇒ 제너레이터 오브젝트를 생성 및 반환하며 함수코드를 이 땐 실행하지 않습니다.
  6. console.log(obj.next());
    ⇒ 제너레이터 오브젝트는 이터레이터 오브젝트이기 때문에 next() 메소드를 사용할 수 있고, 이를 호출할 때 함수코드가 실행되어 평가 결과가 반환됩니다.

yield 키워드

[returnValue] = yield[표현식]

yield 키워드는 next()로 호출할 때마다 하나씩 실행되며 여러개의 yield가 있다면 next()를 호출할 때마다 차례대로 실행 후 반환됩니다. yield 키워드는 제너레이터 함수 실행을 멈추거나 다시 실행할때 사용합니다

예를 들어 제너레이터 함수 내에 yield가 3개가 있다고 할 때 next()를 호출하면 첫 yield 우측 표현식이 평가되어 결과가 반환되면 거기서 함수는 종료합니다.

그리고 다시 next()를 호출할 때 다음 yield 우측 표현식이 평가되어 반환되며 진행되죠. 여기서 표현식을 작성하지 않을 경우에는 undefined가 반환됩니다.

[returnValue]는 오른쪽의 평가 결과가 설정되지 않고 다음 next()에서 파라미터로 넘겨준 값이 설정됩니다. const returnValue = yield 10;이라면 10이 설정되는 것이 아니라 다음 next()호출 시 넘겨주는 파라미터 값이 returnValue에 설정된다는 의미입니다.

function* sports(one) { 
  yield one + 10;
  yield;
  const value = yield one + 50;
};
const obj = sports(30);
console.log(obj.next());
console.log(obj.next());
console.log(obj.next());
console.log(obj.next(200));
// {value: 40, done: false}
// {value: undefined, done: false}
// {value: 80, done: false}
// {value: undefined, done: true}
  • console.log(obj.next(200));
    • 제너레이터 함수 sports는 3개의 yield가 있습니다. 따라서, 3번의 next() 호출까지는 상응하는 yield 우측 표현식의 평가 결과를 반환합니다.
    • 네 번째 obj.next(200)을 호출 할 때는 더 이상의 yield가 존재하지 않아 undefined가 호출되며, 이 때 넘겨준 200은 코드 내 const value가 [returnValue]이기에 200이 설정되지만 yield가 없어 반환할 값이 없기에 undefined가 출력됩니다.

yield의 표현식을 평가하면 호출한 곳으로 {value: 값, done: true/false}를 반환합니다.

function* sports(one) {
  yield one;
  const check = 20;
};
const obj = sports(10);
console.log(obj.next());
console.log(obj.next());
// {value: 10, done: false}
// {value: undefined, done: true}
  1. obj.next()
    ⇒ yield one; 실행되어 {value:10, done:false}반환
  2. obj.next() 두 번째 호출
    ⇒ check = 20을 실행하지만 yield가 아니기에 {value: undefined, done:true} 반환
  • 여기서 yield의 반환 형태는 {value, done}인데
    • value는 표현식의 평가 결과를 설정하며, yield를 설정하지 못하면 undefined를 설정합니다.
    • done은 yield의 실행 여부를 설정하는데 실행할 경우 false를 설정하며, 실행하지 못했을경우 true를 설정합니다.

정리

function* sports(one) { 
  let two = yield one;
  let param = yield one + two;
  yield param + one;
};
const obj = sports(10);
console.log(obj.next());
console.log(obj.next());
console.log(obj.next(20));
console.log(obj.next());
// {value: 10, done: false}
// {value: NaN, done: false}
// {value: 30, done: false}
// {value: undefined, done: true}
  1. const obj = sports(10);
    ⇒ sports 제너레이터 오브젝트를 생성하며 파라미터 값으로 10을 작성해 one에 설정됩니다.
  2. 첫 번째 console.log(obj.next());
    ⇒ let two = yield one;이 실행되며 one에 설정된 값인 10이 반환됩니다.
    ⇒ 이 때 two는 [returnValue]이기 때문에 10을 할당하지 않습니다. 다음 next()에서 전달되는 파라미터가 설정됩니다.
  3. 두 번째 console.log(obj.next());
    ⇒ 두 번째 next()호출시 파라미터를 작성하지 않았기 때문에 [returnValue]인 two는 undefined입니다.
    ⇒ 두 번째 yield의 우측 표현식 one + two는 10 + undefined이기 때문에 NaN이 반환됩니다.
  4. 세 번째 console.log(obj.next(20));
    ⇒ 여기서 작성한 파라미터 값은 다음 [returnValue]인 param에 설정됩니다.
    ⇒ 세 번째 yield의 우측 표현식은 param+one으로 20 + 10이 되어 30이 반환됩니다.
  5. 네 번째 console.log(obj.next());
    ⇒ 네 번째 이후 next() 호출은 더 이상 실행할 yield가 없기에 처리하지 않고, value는 undefined이고 done은 true를 반환합니다.

next()

  • next()는 yield 단위로 실행
    GeneratorObject에서 next()의 호출은 yield 수 만큼 할 수가 있으며, 수 만큼 호출이 끝나면 그 뒤로는 next()를 호출해도 {value: undefined, done: true}가 출력됩니다.

  • next()의 실행 범위
    next()를 호출하면 이전 yield의 표현식 종료 지점부터 다음 yield 표현식 종료까지 실행합니다.

    function* sports(value) {
      value += 20;
      const param = yield ++value;
      value = param + value;
      yield ++value;
    };
    const obj = sports(10);
    console.log(obj.next());
    console.log(obj.next(20));
    // {value: 31, done: false}
    // {value: 52, done: false}
    1. console.log(obj.next());
      • value += 20; 실행
      • const param = yield ++value; 실행
    2. {value: 31, done: false} 반환
    3. const param = yield ++value;
      • param에 값을 할당하지 않습니다.
    4. console.log(obj.next(20));
      이전 yield의 표현식 종료 지점부터 다음 yield 표현식 종료까지 실행
    5. 다음 yield는 20을 param에 설정하는 것을 뜻합니다.
    6. 20 + 31은 51이 되며 yield ++value에서 1을 더해 52를 반환합니다.
  • yield를 미작성

    function* sports(value) {
      ++value;
      console.log(value);
    };
    const obj = sports(10);
    console.log(obj.next());
    // 11
    // {value: undefined, done: true}

    ⇒ next()를 호출하면 제너레이터 함수를 실행하여 value 값은 증가하지만, yield가 없으므로 값이 반환되지 않습니다.

  • return문 작성

    function * sports(value){
    	return ++value;
    };
    const obj = sports(10);
    console.log(obj.next());
    console.log(obj.next());
    // {value: 11, done: true}
    // {value: undefined, done: true}

    ⇒ next()를 호출하면 제너레이터 함수를 실행하여 증가된 value값을 반환합니다.
    ⇒ 하지만, return으로 값을 반환하면 {done: true}이며 이터레이션이 종료됩니다. 더 이상 호출해도 반환값이 없습니다.

변숫값을 그대로 유지

일반적인 함수는 호출할 때 마다 변수의 초기값(undefined)를 설정하는 작업을 거칩니다. 하지만, 제너레이터 함수는 다릅니다.

  • 제너레이터 오브젝트를 생성할 때 초깃값을 설정
  • next()로 실행할 때 마다 초깃값을 설정하지 않음
  • 변숫값을 그대로 유지

제너레이터 함수에 파라미터로 10을 작성하고 next()를 호출하며 [returnValue]에 값을 세팅하는 것들과 평가결과 등이 모두 저장됩니다. 이 후 다음 next()를 호출할 때 yield 표현식이 평가될 때 사용합니다.

마치 비디오 테이프의 pause/play와 같습니다. 일반 함수가 로직을 완전히 수행 후 종료되어 재호출하면 처음부터 다시 시작한다면, 제너레이터 함수는 1회성이며 next()를 호출 할 때마다 yield에 따라 함수 실행이 진행됩니다.

const sports = function* (param) {
  const one = param + 10;
  yield one;
  var two = 2;
  yield one + two;
};
const obj = sports(10);
console.log(obj.next());
console.log(obj.next());
  1. const obj = sports(10);
    제너레이터 오브젝트를 생성하는 단계에서 파라미터를 할당하고 초깃값을 설정합니다.

  2. 두 번째 console.log(obj.next());
    next()로 실행할 때 마다 초깃값을 설정하지 않기에 첫 번째 next()에서 실행하여 설정된 변수들이 유지됩니다.


yield 반복, 다수의 yield

yield 반복

동적으로 yield를 사용하거나 반복문(while, for..)를 통한 사용시 반드시 중단점을 설정해야 합니다.

let status = true;
function* sports() {
  let count = 0;
  while(status) {
    yield ++count;
  };
}
const obj = sports();
console.log(obj.next());
console.log(obj.next());
status = false;
console.log(obj.next());
// {value: 1, done: false}
// {value: 2, done: false}
// {value: undefined, done: true}
  1. console.log(obj.next());
    ⇒ obj.next()를 호출하여 제너레이터 함수 sports의 코드를 실행합니다.
  2. while(status) {yield ++count;};
    • status가 true이므로 yield를 수행하며 yield 우측 표현식 ++count의 평가결과 {value: 1, done: false}이 반환됩니다.
    • 두 번째 next()를 실행시 반복문을 실행하며 ++count의 평가결과 {value: 2, done: false}이 반환됩니다.
  3. status = false;
    ⇒ 전역 변수 status의 값을 true에서 false로 설정합니다.
  4. console.log(obj.next())
    ⇒ status가 false가 되었으므로 반복문을 수행하지 않습니다.
    {value: undefined, done: true}을 반환하고 done이 true이므로 이터레이터를 더 이상 사용할 수 없습니다.

다수의 yield

한 줄에 다수의 yield와 return을 작성하여 처리할 수도 있습니다.

function* sports(){
  return yield yield yield;
};
const obj = sports();
console.log(obj.next());
console.log(obj.next(10));
console.log(obj.next(20));
console.log(obj.next(30));
// {value: undefined, done: false}
// {value: 10, done: false}
// {value: 20, done: false}
// {value: 30, done: true}
  1. console.log(obj.next());
    ⇒ 첫 번째 yield를 수행합니다. 이때 yield의 반환 값이 없기에 {value: undefined, done: false}를 반환합니다.
  2. console.log(obj.next(10));
    • 두 번째 next()를 호출하며 파라미터로 10을 작성했습니다. sports() 제너레이터 함수내부의 다음 yield를 수행합니다.
    • 여기서 파라미터로 작성한 값을 받을 변수가 없다면 파라미터로 념겨준 값을 반환합니다.
    • {value: 10, done: false}를 반환합니다.
  3. console.log(obj.next(20));
    ⇒ 두 번째와 마찬가지로 동작하며 {value: 20, done: false}를 반환합니다.
  4. console.log(obj.next(30));
    • 네 번째 next()를 호출할 때는 제너레이터 함수에 처리할 yield가 없습니다.
    • 그렇기에 return문법에 따라 파라미터로 작성한 값 30을 반환하며 {value: 30, done:true}를 반환합니다.
    • 만약 여기서 return문을 작성하지 않으면 {value: undefined, done:true}를 반환합니다.

yield 분할 할당, for-of 반복

yield 분할 할당

yield를 대괄호 안에 여러개 작성할 수도 있습니다.

function* sports() {
  return [yield yield];
};
const obj = sports();
console.log(obj.next());
console.log(obj.next(10));
const last = obj.next(20);
console.log(last);
console.log(last.value);
// {value: undefined, done: false}
// {value: 10, done: false}
// {value: [20], done: true}
// [20]
  1. obj.next(), obj.next(10)
    • 첫 번째와 두 번째 next() 호출은 기존의 yield 상응과 동일합니다.
    • 표현식이 없기에 전달받은 파라미터를 출력하며 각각 {value: undefined, done: false}, {value: 10, done: false}를 반환합니다.
  2. 세 번째 obj.next(20)
    • 받아서 처리할 yield가 없기에 return문을 사용하게 되고 우측의 표현식인 [ ]에 설정되어 [20]으로 반환됩니다.
    • {value:[20], done:true}

for-of 반복

제너레이터 함수를 매번 next()를 호출하여 반환 오브젝트{value, done}에서 꺼내어 쓰고, 또 done을 검사해 추가 반복 가능성 여부를 검사하는 것은 불편합니다.

따라서, 이터레이터 오브젝트인 제너레이터 함수이기에 for-of사용하여 필요한 결과를 얻는 것이 가능합니다. next()와 달리 value만 받아오기에 반복문을 종료시키는 작업이 필요합니다.

function* sports(count) {
  while(true) {
    yield ++count;
  };
};
for (let point of sports(10)) {
  console.log(point);
  if(point > 12) {
    break;
  };
}
// 11
// 12
// 13
  1. for (let point of sports(10)){...}
    • 처음 for-of문을 시작하면 sports(10)으로 제너레이터 오브젝트를 생성하고, 작성한 파라미터 10이 count에 설정됩니다.
    • 이 때 생성한 제너레이터 오브젝트를 저장할 변수가 없으며 엔진 내부에 저장합니다.
    • const engine = sports(10);와 같으며 engine이 엔진 내부의 이름으로 가정합니다.
  2. for-of문으로 다시 sports*()를 호출하고, 이는 next()와 동작은 같지만 반환 값이 다릅니다.
    • 기존 next()가 {value: , done: }으로 반환한다면, for-of에서는 value만 point에 설정합니다.
  3. while문에서 done:true를 이용하여 종료할 수 없기 때문에 break문으로 종료시켜야 합니다.
  4. for-of 블록을 실행합니다.
    • 11을 출력하고 if문으로 비교 후 다시 for-of문을 수행합니다.
    • while문 속에서 count 값이 증가하게 됩니다.
  5. break를 만날 때 까지 반복하여 yield를 실행합니다.

제너레이터 오브젝트 메소드

return()

이터레이터를 종료시키는 메소드입니다. 파라미터로 작성한 값을 반환값으로 가져옵니다. 기존의 next()가 play/pause와 비슷하다면 return()은 stop이라 볼 수 있습니다.

function* sports(count) {
  while(true) {
    yield ++count;
  };
};
const obj = sports(10);
console.log(obj.next());
console.log(obj.return(70));
console.log(obj.next(50));
// {value: 11, done: false}
// {value: 70, done: true}
// {value: undefined, done: true}
  1. obj.return(70)
    ⇒ 이터레이터를 종료시키며 파라미터 값 70을 반환합니다. 이때 done:true가 됩니다. 이는 이터레이터가 종료되어 진행이 불가능해진다는 의미입니다.
  2. obj.next(50)
    ⇒ 이터레이터가 종료되었으므로 {value: undefined, done:true}가 반환됩니다. 파라미터 50이 반환되지 않습니다.

throw()

의도적으로 Error를 발생시켜 예외상황을 유도할 때 사용하는 메소드입니다. 제너레이터 함수의 catch()문에서 에러를 받습니다.

  • throw() 메소드

    function* sports(){
      try {
        yield 10;
      } catch(message){
        yield message;
      };
      yield 20;
    };
    const obj = sports();
    console.log(obj.next());
    console.log(obj.throw("에러 발생"));
    console.log(obj.next());
    // {value: 10, done: false}
    // {value: 에러 발생, done: false}
    // {value: 20, done: false}
  • throw 문

    function* sports() {
      throw "에러 발생";
      yield 10;
    }
    const obj = sports();
    try {
      const result = obj.next();
    } catch(message){
      console.log(message);
    }
    console.log(obj.next());
    // 에러 발생
    // {value: undefined, done: true}

    ⇒ obj.next()를 실행하면 제너레이터 안에서 throw를 만나며 에러가 발생됩니다. 이렇게 제너레이터 함수에서 에러가 발생하면 이터레이터는 종료됩니다.
    ⇒ 따라서, 마지막 줄에서 next()를 호출해도 {value: undefined, done:true}를 반환할 뿐, yield 10;은 실행되지 않습니다.


yield* 표현식

yield* expression

yield에 *키워드를 붙히면 우측의 표현식에 따라 다른 처리로직을 따르게 되는데요. 기본 골조는 play/pause를 유지하지만, 그 처리되는 방식이 달라집니다.

표현식이 배열인 경우

yield*의 표현식이 배열인 경우 next()를 호출할 때마다 배열의 엘리먼트를 순서대로 반환한 뒤 다음 yield를 찾습니다.

function* sports() {
  yield* [10, 20];
};
const obj = sports();
console.log(obj.next());
console.log(obj.next());
console.log(obj.next());
// {value: 10, done: false}
// {value: 20, done: false}
// {value: undefined, done: true}
  1. 첫 번째 obj.next() 호출
    yield* [10, 20]에서 첫 번째 요소인 10을 반환합니다.
  2. 두 번째 obj.next() 호출
    yield* [10, 20]에서 두 번째 요소인 20을 반환합니다.
  3. 세 번째 obj.next() 호출
    다음의 yield가 없기에 {value: undefined, done: true}로 이터레이션을 종료합니다.

표현식이 제너레이터 함수인 경우

function* point(count) {
  yield count + 5;
  yield count + 10;
};
function* sports(value) {
  yield* point(value);
  yield value + 20;
};
const obj = sports(10);
console.log(obj.next());
console.log(obj.next());
console.log(obj.next());
// {value: 15, done: false}
// {value: 20, done: false}
// {value: 30, done: false}
  1. 첫 번째 obj.next() 호출
    • 제너레이터 함수 sports의 yield* point(value)를 실행합니다.
    • point()는 제너레이터 함수이기에 우선 제너레이터 오브젝트를 생성합니다.
    • 기존 원리라면 여기서 next()를 호출해야 yield가 수행되지만 자동으로 point()의 첫 번째 yield count + 5;가 수행되어 {value: 15, done: false}를 반환합니다.
    • sports()에서 받고 다시 반환합니다.
  2. 두 번째 obj.next() 호출
    • 마지막으로 호출된 point 함수 안의 위치에서 시작해 다음 yield를 실행해 count + 10;을 반환하며 sports()에서 받고 다시 반환합니다.
  3. 세 번째 obj.next() 호출
    • 현재 수행되던 제너레이터 함수 point()의 yield를 모두 처리했기에 다음 yield value + 20;을 실행하여 반환합니다.

표현식이 재귀함수인 경우

function* sports(point) {
  yield point;
  yield* sports(point + 10);
};
const obj = sports(10);
console.log(obj.next());
console.log(obj.next());
console.log(obj.next());
// {value: 10, done: false}
// {value: 20, done: false}
// {value: 30, done: false}
  1. 첫 번째 obj.next() 호출
    yield point; 실행하여 반환 - {value: 10, done: false}
  2. 두 번째 obj.next() 호출
    yield* sports(point + 10);으로 자기자신을 호출하며 첫 번째 라인의 yield point;를 실행하여 {value: 20, done: false}이 반환됩니다.
  3. 세 번째 obj.next() 호출
    2번째와 마찬가지로 yield* sports(point + 10)를 호출하며 첫 번째 줄의 yield point를 실행합니다.
  • [주의] 첫 번째 줄의 yield point;가 없으면 무한반복을 하게 됩니다.
profile
소신있게 정진합니다.

0개의 댓글