대가는 결과를 만든다

iterator/iterable, generator에 대한 정리 본문

개발/Javascript

iterator/iterable, generator에 대한 정리

yunzema 2020. 3. 24. 16:28
반응형

이터러블/이터레이터

이터러블/이터레이터 프로토콜 : 이터러블을 ES6의 for...of, 전개 연산자 등으로 동작하도록한 규약이다. 오픈소스나 브라우저에서 이 규약을 통해 ES6의 문법을 사용할 수 있도록 이터러블/이터레이터 프로토콜로 구현되어져 있는 부분들이 많이 있다. 예) immutable.js나 브라우저 dom API 등..

 

 

1. 이터러블 : 이터레이터를 리턴하는 [Symbol.iterator]( )를 가진 값

//iteraable

iterable = {
		[Symbol.iterator](){
			return iterator;
		}
}

2. 이터레이터 : {value, done} 객체를 리턴하는 next( )를 가진 값

iterator = {
	next(){
		return i==0 ? {done:true} : {value: i--, done: false};
	}
}

3. well formed iterator

//wellformed iterable을 직접 정의

const iterable = {

	//[Symbol.iterator]
	[Symbol.iterator](){
    		let i = 3;
        
        	//iterator를 리턴
        	return {
        		//next함수 정의 : done이 true가 될 대까지, value를 3부터 감소하며 순회
        		next(){
            			return i == 0 ? {done: true} : {value: i--, done: false};
            		},
            		//자기 자신을 리턴하여 계속 진행될 수 있도록 하는 것이 well formed iterator 이다.
            		[Symbol.iterator]() { return this; }
        	}
    	}
}
let iterator = iterable[Symbol.iterator]();

iterator.next();	//well formed iterator이기 때문에, 지나고 나서 순회도 가능

for (const a of iterator) console.log(a);

//2, 1을 출력

// 아래와 같이 iterable도 순회가 가능 well formed iterator이기 때문
// for (const a of iterable) console.log(a);

4. 전개 연산자 : iterator/iteratable 프로토콜을 사용하는 객체 모두 전개연산자 사용이 가능하다

//전개연산자 테스트

const a = [1,2];
const map = new Map([['key1', 'value1'], ['key2', 'value2']]);	//key,value 형태로 저장되는 객체
const set = new Set([1,2,3]);					//고유한 원소들만 갖는 객체

console.log([...a, ...set, ...map, ...map.keys()]);
//[1, 2, 1, 2, 3, ['key1','value1'], ['key2', 'value2'], 'key1', 'key2']를 출력

 

generator/iterator

- generator는 iterator이자 iterable을 생성하는 함수

- generator를 통해 순회할 수 있는 값으로 직접 정의해서 만들 수 있다.

 

1. 기본적인 generator 만들어보기

//iterable/iterator를 생성하는 generator 함수를 정의
function *gen(){
	yield 1;
    if (false) yield 2;
    yield 3;
}

//generator로 생성
let iter = gen();

console.log(iter[Symbol.iterator]()) == iter);
//iterator인지 체크 :  true를 출력

for (const a of iter) console.log(a);
//1, 3을 출력

2. generator를 조금 더 복잡하게 사용해보기

: 세개의 generator 함수를 통해 원하는 범위까지 홀수값을 출력하는 iterator를 만들어보자

//시작 값을 파라미터로 받아 계속 추가하는 generator
//**iterator에서 next가 호출될 때마다 값이 추가되는 것이므로, 무한반복문으로 멈추거나 하지 않는다
function *infinity(i=0){
	while (true) yield i++;
}

//iterator와 한계값을 받아 한계값이 도달할 때 까지만 iterator의 값을 iterator에 추가
//function *limit(l, iter){
	for (const a of iter){
    	yield a;			//iterator의 값 추가
    	if(a==l) return;	//한계값에 도달하면 리턴
    }
}

//전달받은 한계값 까지 홀수만 가지는 iterator를 생성하는 generator 정의
function *odds(l){
	//한계값 까지 계속 증가하는 iterator를 생성
	let newIt = limit(l, infinity(1));
    
    //한계값까지 1씩 증가하는 값을 가진 iterator에서 홀수만 생성하는 iterator에 추가하도록함
	for(const a of newIt){
    	if(a%2) yield a;
    }
}

let iter2 = odds(10);
for (const a of iter2) console.log(a)
//1,3,5,7,9 출력
// 위에서 정의한 odds generator를 이용한 전개 연산자, 구조분해, 나머지 연산자 테스트

//전개 연산자
console.log(...odds(10));			//1 3 5 6 7 9 출력
console.log([...odds(10), ...odds(20)]); 	//[1,3,5,7,9,1,3,5,7,9,11,13,15,17,19] 출력

//구조분해, 나머지 연산자
const [head, ...tail] = odds(5);
console.log(head);		//1 출력
console.log(tail);		//[3,5] 출력

const [a,b, ...rest] = odds(10);
console.log(a);		//1 출력
console.log(b);		//3 출력
console.log(rest);	//[5,7,9] 출력
Comments