자바스크립트
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());
}