#1 제너레이터와 이터레이터
제너레이터 함수란?
ES6에서 도입된 제너레이터(Generator) 함수는 이터러블을 생성하는 함수이다. 제너레이터 함수를 사용하면 이터레이션 프로토콜을 준수해 이터러블을 생성하는 방식보다 간편하게 이터러블을 구현할 수 있다. 또한 제너레이터 함수는 비동기 처리에 유용하게 사용된다.
function* gen() {
yield 1;
yield 2;
yield 3;
}
const genIter = gen();
console.log(genIter.next()); // {value:1, done: flase}
console.log(genIter.next()); // {value:2, done: flase}
console.log(genIter.next()); // {value:3, done: flase}
console.log(genIter.next()); // {value:undefined, done: true}
위 코드를 보면 제너레이터 함수는 일반 함수와 동일한 동작을 하는것 처럼 보인다. 하지만 아래 코드를 보자.
function* gen() {
console.log('첫번째');
yield 1;
console.log('두번째');
yield 2;
console.log('세번째');
}
const genIter = gen();
console.log(genIter.next()); // 첫번째 {value:1, done: flase}
console.log(genIter.next()); // 두번째 {value:2, done: flase}
console.log(genIter.next()); // 세번째 {value:undefined, done: true}
다시말해서, 제너레이터 함수는 일반 함수와는 다른 동작을 하는데, 제너레이터 함수는 일반 함수와 같이 함수의 코드 블록을 한 번에 실행하지 않고 함수 코드 블록의 실행을 일시 중지했다가 필요한 시점에 재시작할 수 있는 특수한 함수이다. 즉, 제너레이터는 문장을 통해 순회할 수 있는 값을 만들 수 있으며, 어떠한 값도 제너레이터를 통해 순회할 수 있는 형태로 조작할 수 있다.
제너레이터 함수의 정의
먼저 제너레이터 함수를 선언하고 이용하는 방법을 간단하게 알아보자.
function* gen() {
yield 1;
yield 2;
return 100;
}
const genIter = gen();
console.log(genIter.next()); // {value:1, done: flase}
console.log(genIter.next()); // {value:2, done: flase}
console.log(genIter.next()); // {value:100, done: true}
제네레이터 함수의 선언은 function 앞에 *을 붙여서 function* func() 형식으로 선언하면 된다. 그리고 yield를 통해서 몇 번의 next()를 할 수 있는지를 결정할 수 있으며, return값을 설정함으로써 done이 true가 되는 시점에 value값을 리턴할 수 있다.
※단, 기본적으로 순회하면서 조회할때는 리턴값은 무시된다.
제네레이터 함수의 활용
제네레이터 함수를 활용해 간단하게 홀수만 계속해서 발생시키는 이터레이터를 만들어보자.
function* odds(l){
for (let i = 0; i < l; i++){
if (i % 2) yield i;
}
}
const genIter = odds(10);
console.log(genIter.next()); // {values: 1, done: false}
console.log(genIter.next()); // {values: 3, done: false}
console.log(genIter.next()); // {values: 5, done: false}
console.log(genIter.next()); // {values: 7, done: false}
console.log(genIter.next()); // {values: 9, done: false}
console.log(genIter.next()); // {values: undefined, done: true}
다음과 같이 활용도 가능하다.
function* infinity(i = 0) {
while (true) yield i++;
}
function* limit(l, iter) {
for (const a of iter) {
yield a;
if (a == l) return;
}
}
function* odds(l){
for (const a of limit(l, infinity(1))) {
if (a % 2) yield a;
}
}
const genIter = odds(10);
console.log(genIter.next()); // {values: 1, done: false}
console.log(genIter.next()); // {values: 3, done: false}
console.log(genIter.next()); // {values: 5, done: false}
console.log(genIter.next()); // {values: 7, done: false}
console.log(genIter.next()); // {values: 9, done: false}
console.log(genIter.next()); // {values: undefined, done: true}
'Web[웹] > ES6+ 함수형 언어' 카테고리의 다른 글
[JS: ES6+] 제너레이터/이터레이터 프로토콜로 구현하는 지연 평가 (1) (0) | 2019.10.08 |
---|---|
[JS: ES6+] 장바구니 예제로 코드를 줄이고 HTML로 표현해보기 (0) | 2019.10.07 |
[JS: ES6+] 코드를 값으로 다루어 표현력 높이기 (go, pipe) (0) | 2019.10.04 |
[JS: ES6+] 이터러블 프로토콜을 따른 map, filter, reduce (0) | 2019.10.02 |
[JS: ES6+] ES6에서의 순회와 이터러블:이터레이터 프로토콜 (0) | 2019.09.30 |