
Generator 함수의 실행을 중간에 멈췄다가 재개할 수 있는 객체이다.
Generator 함수는 일반 함수이지만, Generator 함수를 호출하면 일반 함수와는 달리 Generator 객체를 반환한다.
function* fn() {
yield 1;
yield 2;
yield 3;
return "finish";
}
const a = fn();
Generator 함수는 function 옆에 *을 써서 만든다. 함수의 실행을 멈추는 yield 키워드를 Generator 함수 내부에서 사용한다.

Generator 함수를 호출하면 Generator 객체를 반환한다.
function* fn() {
yield 1;
yield 2;
yield 3;
return "finish";
}
const a = fn();
next() 메서드는 Generator 함수 내에서 yield문을 만날 때까지 실행되고, 데이터 객체를 반환한다.

데이터 객체는 value와 done 속성을 가진다. value는 yield가 반환하는 값이다. 값을 생략하면 undefined가 속성값으로 된다.
done은 Generator 함수 코드가 끝났는지를 나타낸다. Generator 함수 코드가 끝난 상태에서 next() 메서드를 호출하면 더 이상 표현할 값이 없기에 value는 undefined를 가지고, done은 true 값을 가진다.
function* fn() {
yield 1;
yield 2;
yield 3;
return "finish";
}
const a = fn();
위와 같은 코드가 정의되어 있다고 하자.

Generator 객체의 인스턴스 메서드 return()을 호출하면 반환되는 데이터 객체의 done 속성은 true인 값을 가진다. 반환된 객체의 value는 return() 함수의 인자가 된다.

이후에 next()를 호출해도 value는 받아올 수 없고 done은 true 값을 가진다. 왜냐하면 return() 메서드를 호출함으로써 Generator 함수의 실행이 즉시 종료되었기 때문이다.
function* fn() {
try {
yield 1;
yield 2;
yield 3;
return "finish";
} catch (e) {
console.log(e);
}
}
const a = fn();
throw() 메서드는 Generator 함수 내부로 오류를 던지기 위해 사용하는 메서드이다. throw() 메서드를 호출하면 Generator 함수가 실행 중이던 위치로 예외를 던져준다. Generator 함수 내부에서는 try...catch를 사용하여 던져진 오류를 처리할 수 있다.
오류를 던지면 catch문에 있는 내용이 실행된다. 만약, catch문 안에 yield가 있고 함수 코드가 아직 끝나지 않았다면, throw()는 value를 yield의 반환값으로 하고 done을 false로 하는 데이터 객체를 반환한다.

위 코드에서는 catch문 안에 yield가 없고, 함수 코드는 끝이 났다. 따라서, throw()는 value가 undefined이고 done은 true인 데이터 객체를 반환한다.
반복이 가능하다는 의미이다. 반복 가능하는 것은 객체가 자신의 요소를 순차적으로 반환할 수 있다는 것이다.
모든 iterable한 객체는 [Symbol.iterator] 메서드를 가진다. 다시말해, iterable한 객체는 Symbol.iterator 심볼값인 프로퍼티를 갖는다. 이때, Symbol.iterator 프로퍼티는 Iterator 객체를 반환하는 함수를 값으로 가진다. Iterator 객체는 iterable한 객체의 요소를 순차적으로 반환해주는 역할을 한다.
Iterator는 value와 done 속성을 가진 객체를 반환하는 next() 메서드를 가진다. 따라서 Generator는 iterable하면서 Iterator이다.
Symbol을 객체의 키로 사용할 때, 대괄호 표기법을 반드시 사용해야 한다.
const sym = Symbol("unique");
const obj = {
[sym] : "value for symbol key",
};
console.log(obj[sym]); // "value for symbol key"
// 점 표기법은 사용할 수 없음
console.log(obj.sym); // undefined
따라서, Symbol.iterator는 유일한 심볼 값으로, 해당 심볼을 키로 사용하기 위해서는 대괄호 표기법으로 정의하고 접근해야한다.
const obj = { [Symbol.iterator]: function {return "Iterator"}};
// obj[Symbol.iterator]는 Symbol.iterator 키의 값으로 저장된 함수 자체를 참조
console.log(obj[Symbol.iterator]);
// 값인 함수 호출
console.log(obj[Symbol.iterator]()); // "Iterator"
| . 표기법 | 대괄호 표기법 |
|---|---|
| 속성 이름이 문자열로 고정된 경우에만 사용한다. | 표현식을 사용하여 속성의 이름을 동적으로 결정(computed property)하거나 심볼을 사용할 때 필요하다. |
iterable, 즉 반복 가능한 객체는 다음과 같은 문법에서 사용할 수 있다.
for...of 반복문const arr = [1, 2, 3];
for (const value of arr) {
console.log(value); // 1 2 3
}
const arr = [1, 2, 3];
const newArr = [...arr, 4, 5];
console.log(newArr); // [1, 2, 3, 4, 5]
Array.from()const str = "hello";
const arr = Array.from(str);
console.log(arr); // ['h', 'e', 'l', 'l', 'o']
const [first, ...rest] = [1, 2, 3];
console.log(first); // 1
console.log(rest); // [2, 3]
배열을 구조 분해 할당한 것으로, 아래 코드와 동일하다.
const first = 1;
const rest = [2,3];
const arr = [1, 2, 3, 4, 5];
const it = arr[Symbol.iterator]();
arr[Symbol.iterator]()는 배열의 Iterator를 생성하는 코드이다.

Iterator는 next() 메서드를 통해 배열의 요소를 하나씩 반환한다.
function* fn() {
yield 1;
yield 2;
yield 3;
return "finish";
}
const a = fn();
a[Symbol.iterator]() === a; // true
Generator는 Iterator 객체임을 알 수 있다.
function* fn() {
const num1 = yield "첫번째 숫자를 입력해주세요.";
console.log(num1);
const num2 = yield "두번째 숫자를 입력해주세요.";
console.log(num2);
return num1 + num2;
}
const a = fn();
Generator 객체는 외부로부터 next() 메서드의 인자를 입력 받을 수 있다. next() 메서드의 인자는 yield 키워드로 일시 정지된 지점에서 값을 할당받는 변수에 저장된다. 따라서, 두 번째 next() 호출에서 전달된 값은 num1에 할당되고, 세 번째 next() 호출에서 전달된 값은 num2에 할당된다.

Generator객체를 사용하면 필요한 순간까지 계산을 미룰 수 있다. 따라서 메모리 관리 측면에서 효율적이다.
function* fn() {
let index = 0;
while(true) {
yield index++;
}
}
const a = fn();

Generator객체는 필요한 순간에만 연산하여 값을 주기에, while(true)문으로 무한 반복할지라도 브라우저가 뻗지 않는다. Generator 객체는 next() 메서드를 호출할 때마다 값을 주기 때문이다. Generator 함수를 사용하지 않았다면, break 없는 while(true)문은 사용해선 안된다.
function* gen1() {
yield "w";
yield "o";
yield "r";
yield "l";
yield "d";
}
function* gen2() {
yield "Hello,";
yield* gen1();
yield "!";
}
yield*을 이용해서 다른 Generator 함수를 호출 할 수 있다. yield* gen1()은 gen1() 함수의 모든 yield 값을 순차적으로 반환한다.

gen2() 함수를 호출해서 Generator 객체를 반환 받는다. 이때, 전개구문을 사용하여 iterable한 Generator 객체에서 값을 모두 꺼내어 개별 요소로 나열한다. 이때 개별 요소란 yield의 값을 말한다. 따라서, "Hello,"부터 "!"까지 반환되어 출력된 것을 볼 수 있다.