제너레이터는 ES6에 도입된 특수한 함수다. 함수 호출자가 함수 실행을 제어할 수 있고, 함수 호출자와 함수 상태를 주고받을 수도 있다. 이런 특징 때문에 제너레이터 함수에선 코드 블록의 실행을 잠시 멈췄다가 필요한 시점에 재개할 수 있다. 일반 함수는 0~1개 값만 반환할 수 있지만, 제너레이터 함수는 여러개의 값을 필요에 따라 하나씩 반환할 수 있다.
<aside> 💡 제너레이터 함수는 이터러블이다. 따라서 함수 자체에 전개 문법을 사용할 수도 있다.
</aside>
제너레이터 함수는 function*
키워드로 선언하고 함수 본문엔 1개 이상의 yield
표현식을 포함한다. 나머진 일반 함수를 정의하는 것과 동일하다. *
기호는 애스터리스크(Asterisk)라고 부르며 function
키워드와 함수 이름 사이라면 어디에 붙여도 상관없다. 대부분은 function
키워드 바로 뒤에 붙인다. ex) function*
// 선언식
function* genDecFunc() {
yield 1;
}
// 표현식
const genExpFunc = function* () { /* ... */ }
// 객체 메서드
const obj = {
* genObjMethod() { /* ... */ }
}
// 클래스 메서드
class MyClass {
* genClsMethod() { /* ... */ }
}
❗️ 제너레이터 함수는 화살표 함수로 정의할 수 없고, new
연산자를 사용하는 생성자 함수로 호출할 수 없다.
const genArrowFunc = * () => { /* ... */ } // Error! Unexpected token '*'
function* genFunc() { /* ... */ }
new genFunc(); // Error! genFunc is not a constructor
제너레이터 함수 자체는 이터러블이므로 아래처럼 전개문법을 사용할 수도 있다.
function* generateSequence() {
yield 1;
yield 2;
yield 3;
}
const res = [0, ...generateSequence()] // [0, 1, 2, 3]
console.log(Symbol.iterator in generateSequence.prototype) // true
// 제너레이터 함수는 Symbol.iterator 메서드를 상속받으므로 이터러블이다
제너레이터 함수는 Symbol.iterator
메서드를 상속받으므로 이터러블이다
<aside> 💡 제너레이터 객체는 이터러블(iterable)이면서 이터레이터(iterator)다.
</aside>