제너레이터와 이터레이터
제너레이터
이터레이터이자 이터러블을 생성및 반환하는 함수
function *gen(){ // * 을 붙히면 제너레이터가 된다.
yield 1;
yield 2;
yield 3;
}
let iter = gen();
log(iter[Symbol.iterator]()==iter) // true
log(iter.next()); // {value: 1, done: false}
for(const a of gen()) log(a) // 1,2,3
JavaScript
복사
제너레이터는 순회 할 값을 문장으로 표현하는 것이라고 할 수 있다.
function *gen(){
yield 1;
if(false) yield 2;
yield 3;
}
JavaScript
복사
•
제너레이터는 위와 같은 문장을 값으로 만들 수 있고, 이 문장을 통해 순회할 수 있는 값을 만들 수 있다. 이 말은 어떠한 값이나 상태든 순회할 수 있다는 의미.
•
즉, 어떠한 값도 순회할 수 있도록 조작할 수 있다는 말이 된다.
odds
이용하여 홀수만 반환하여 순회하는 제너레이터 만들어보기
•
직접 입력을 해야만 계속 홀수를 생성하는 제너레이터
function *odds(){
yield 1;
yield 3;
yield 5;
}
let iter2 = odds();
log(iter2.next()); //1
log(iter2.next()); //3
log(iter2.next()); //5
JavaScript
복사
•
홀수 생성을 자동화 한 제너레이터
function *odds(l){
for(let i = 0; i < l; i++){
if(i%2) yield i;
}
}
let iter2 = odds(10);
log(iter2.next()); //1
log(iter2.next()); //3
log(iter2.next()); //5
log(iter2.next()); //7
log(iter2.next()); //9
log(iter2.next()); //undefined
JavaScript
복사
•
무한 수열 제너레이터
function *infinity(i = 0){
while(true) yield i++;
}
let iter3 = infinity();
log(iter3.next()); //{value: 0, done: false}
log(iter3.next()); //{value: 1, done: false}
...
log(iter3.next()); //{value: n, done: false}
JavaScript
복사
•
제한(limit) 제너레이터
function *limit(l, iter){
for(const a of iter){
yield a;
if(a == l) return;
}
}
let iter4 = limit(3, [1,2,3,4,5,6]);
log(iter4.next()) //{value: 1, done: false}
log(iter4.next()) //{value: 2, done: false}
log(iter4.next()) //{value: 3, done: false}
log(iter4.next()) //{value: undefined, done: true}
log(iter4.next()) //{value: undefined, done: true}
JavaScript
복사
•
홀수생성 제너레이터 응용
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;
}
}
let iter2 = odds(10);
console.log(iter2.next());//{value: 1, done: false}
console.log(iter2.next());//{value: 3, done: false}
console.log(iter2.next());//{value: 5, done: false}
console.log(iter2.next());//{value: 7, done: false}
console.log(iter2.next());//{value: 9, done: false}
console.log(iter2.next());//{value: undefined, done: true}
console.log(iter2.next());//{value: undefined, done: true}
for(const a of odds(40)) log(a) // 1,3,5,...39
JavaScript
복사
for...of, 전개연산자, 구조 분해, 나머지 연산자
모두 이터러블 프로토콜을 따르고 있는 함수들이다.
•
사례1 전개연산자와 제너레이터 사용
log(...odds(10)); // 1, 3, 5, 7, 9
log([...odds(10), ...odds(20)]); // [1,3,5,7,9,1,3,5,7,9,11,13,15,17,19]
JavaScript
복사
•
사례2 구조분해와 제너레이터 사용
const [head, ...tail] = odds(5);
log(head); // 1
log(tail); //[3,5]
JavaScript
복사
•
사례3 나머지 연산자와 제너레이터 사용
const [a, b, ...rest] = odds(10);
log(a); // 1
log(b); // 3
log(rest);//[5, 7, 9]
JavaScript
복사
정리
: 많은 라이브러리들이나 함수들이 해당 프로토콜을 따르도록 되어있기에 이터러블/이터레이터를 잘 사용할 수록 조합성이 높은 프로그램 구현이 가능하다.