Generator 이해하기 (2) - 마무리
2025. 9. 26. 16:51

이번 글에서는 자바스크립트의 제너레이터(Generator) 에 대해 마저 알아보겠습니다.


제너레이터 정의

제너레이터 객체는 제너레이터 함수에 의해 반환되며, 이터러블 프로토콜이터레이터 프로토콜을 모두 따릅니다.

쉽게 말해, 제너레이터는 반복문에서 사용할 수 있고 동시에 next()를 호출해 값을 하나씩 꺼낼 수도 있는 객체입니다.


제너레이터의 장점

먼저, 제너레이터를 사용하는 이유부터 살펴보겠습니다.

  • 메모리 효율성: 필요한 시점에만 값을 생성하므로 메모리를 절약할 수 있습니다.
  • Iterable 정의 간소화: Iterable을 간단히 작성할 수 있습니다.
    https://goto-helloworld.tistory.com/146 와 비교하면, 왜 간단한지 이해가 가능합니다. 
  • 상태 제어 용이yield를 통해 실행을 멈췄다가 다시 이어갈 수 있어 흐름 제어가 유연합니다.

 

def simple_generator():
    yield 1
    yield 2
    yield 3

# generator 객체 생성
gen = simple_generator()

print("Generator를 사용한 반복문:")
for value in gen:
    print(value)

제너레이터의 생성과 기본 동작

자바스크립트에는 new Generator라는 생성자가 직접적으로 존재하지 않습니다.

대신 제너레이터 함수를 정의하고 호출하면 Generator 객체가 반환됩니다.

function* generator() {
    yield 1;
    yield 2;
    yield 3;
}

const gen = generator();

console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // 3

위 예시처럼 function*으로 선언한 제너레이터 함수는 호출 시 새로운 Generator 객체를 반환하고,

내부에서 yield 키워드를 통해 값을 하나씩 전달합니다.


제너레이터의 동작 방식

  • 제너레이터 함수는 호출 시 Generator 객체를 반환합니다.
  • 처음 실행 시 함수 본문 맨 앞에서 대기(suspended) 상태로 시작합니다.
  • 여러 번 호출하면 각각 독립적인 실행 컨텍스트를 유지합니다.

호출자와 제어 흐름

  • 호출자는 next(), throw(), return()을 통해 제너레이터를 제어합니다.
  • 제너레이터 내부에서는 yield, yield*, return, throw 등을 통해 호출자에게 제어권을 넘깁니다.

next() 실행 시

  • yield를 만나면 { value: 값, done: false }를 반환하고 멈춥니다.
  • yield*를 만나면 다른 이터러블에 제어를 위임합니다.
  • return이나 함수 종료 시 { value: 반환값, done: true }를 반환하고 종료합니다.

throw()return() 실행 시

  • throw(): 제너레이터 내부에서 예외를 던진 것처럼 동작합니다.
  • return(): 현재 위치에서 return이 실행된 것처럼 동작하며 종료합니다.

 

무한 이터레이터 예시

제너레이터는 필요할 때마다 값을 생성하기 때문에 무한한 데이터 구조도 정의할 수 있습니다.

function* infinite() {
    let index = 0;
    while (true) {
        yield index++;
    }
}

const generator = infinite();

console.log(generator.next().value); // 0
console.log(generator.next().value); // 1
console.log(generator.next().value); // 2

 

제너레이터 내부 값 전달 예시

function* 제너레이터함수() {
    const a = yield 10;
    const b = yield a + 1;
    return a + b + 100;
}

const 제너레이터객체 = 제너레이터함수();

console.log(제너레이터객체.next());     // { value: 10, done: false }
console.log(제너레이터객체.next(20));  // { value: 21, done: false }
console.log(제너레이터객체.next(30));  // { value: 150, done: true }

위 예시에서는 next()에 전달한 값이 제너레이터 내부 yield 표현식 결과로 들어갑니다. 따라서 첫 번째 yield는 10을 반환하고, 두 번째 yield는 외부에서 전달된 20을 사용해 21을 반환합니다. 마지막으로 30이 b 값으로 들어가 최종적으로 150을 반환하고 종료됩니다.

 

yield* 예시

function* anotherGenerator(i) {
    yield i + 1;
    yield i + 2;
    yield i + 3;
}

function* generator(i) {
    yield i;
    yield* anotherGenerator(i); // 다른 제너레이터에 제어를 위임
    yield i + 10;
}

const gen2 = generator(10);

console.log(gen2.next().value); // 10
console.log(gen2.next().value); // 11
console.log(gen2.next().value); // 12
console.log(gen2.next().value); // 13
console.log(gen2.next().value); // 20

👉 yield*를 사용하면 다른 제너레이터나 배열 같은 이터러블 전체를 위임하여 손쉽게 연결할 수 있습니다.


제너레이터 프로토타입

마지막으로, 제너레이터 객체가 어떤 공통 메서드를 가지는지 정리해보겠습니다.

여기서 말하는 프로토타입(prototype) 은 객체가 다른 객체로부터 속성과 메서드를 상속받는 연결 고리를 의미합니다.

제너레이터 객체는 공통된 Generator.prototype을 참조하여 다음과 같은 메서드를 사용할 수 있습니다.

  • next(): yield된 값을 반환하며 실행을 멈추거나 이어갑니다.
  • return(): 현재 위치에서 return문을 실행한 것처럼 제너레이터를 종료합니다.
  • throw(): 현재 위치에서 예외를 발생시킨 것처럼 동작하며, 내부에서 에러 처리를 할 수 있습니다.

참고자료

'FE > JS' 카테고리의 다른 글

Generator 이해하기(1), [Iterable, Iterator]  (0) 2025.09.24
자바스크립트 - 클로저  (0) 2025.05.19
JavaScript - this  (0) 2025.05.19
자바스크립트 실행 컨텍스트  (0) 2025.05.19
자바스크립트 호이스팅 정리  (0) 2025.05.18