Iterator와 Genenerator

Jay K·2022년 5월 19일
0

es6

목록 보기
1/1
post-thumbnail

Iterator(반복자)

Javascript의 Iterator(반복자)는 next 메서드를 가지고 있는 객체이고 이 메서드는 원소들을 탐색하며, next 메서드의 호출시마다 새로운 객체를 반환한다. 반복자는 두 개의 속성(value, done)을 반환하는 next() 메소드 사용하여 객체의 Iterator protocoal을 구현한다.

기본적인 개념을 알았으니 한번 간단한 예시를 들어 사용해보자
밑의 코드는 아래 iterable Array의 원소값을 차례로 나열해줄 수 있게 iterator를 사용한 것이다.

const iterable = [1, 2, 3]

const iterator = iterable[Symbol.iterator]();

while (true) {
	const iteratorResult = iterator.next()
    
    if (iteratorResult.done) break;
    console.log(iteratorResult.value)
}


// 결과 값
/* 
1
2
3
*/

iterator의 탐색이 완료되면 done의 값은 true를 반환하므로 무한루프가 종료된다.

좀 더 심화과정으로 iterator를 이용하여 피보나치 수열을 생성하는 코드를 작성해보자

const fibonacci = {
    [Symbol.iterator]() {
        let n1 = 0, n2 = 1, value;
        return {
            next() {
                value = n1;
                n1 = n2;
                n2 = value + n2;

                if (value > 100) {
                    return {done: true};
                } else {
                    return {value};
                }
            }
        };
    }
};

for (const n of fibonacci) {
    console.log(n);
}
// 실행결과
/*
0
1
1
2
3
5
8
13
21
34
55
89
*/

계산하는 수가 100이상이 되면 return {done: true} 를 통해 iterator 종료된다.

Genarator(생성자)

Genarator(생성자)는 Itearble하면서 Iterator인 객체의 특별한 종류이다. 이 객체는 일시정지와 재시작 기능을 여러 반환 포인트들을 통해 사용이 가능하다. 이런 반환 포인트들은 yield 라는 키워드를 통해 구현이 가능하며 next 를 호출시마다 다음 yield 값이 반환된다. Iterator과 마찬가지로 value와 done이 호출되며 Generator의 yield값이 value값으로 반환이 된다.

이제 간단한 예시를 들어보자

function* generatorFunction() {
	let i = 0;
    while (true) {
    	yield i++
    }
}

const generator = generatorFunction();
console.log(generator.next());
console.log(generator.next());
console.log(generator.next());
console.log(generator.next());

//실행결과
/*
{ value : 0, done: false }
{ value : 1, done: false }
{ value : 2, done: false }
{ value : undefined, done: true }
*/

이처럼 일반함수였으면 while문의 break를 안넣어주었기 때문에 무한루프가 되는 함수 이었지만 generator를 통해 생성된 함수이기 때문에 호출할때마다 i의 값이 1씩 늘어나는 것을 알 수 있다.

그런데 이런 generator를 왜 사용하는 것일까?
이유는 일반 반복문보다 generator를 활용한 코드가 좀더 빠르게 작용하기 때문이다.
밑의 예시 코드를 봐보자

function newArr(n) { 
    let i = 1; 
    const res = []; 
    while (i < n) res.push(i++); 
    return res; 
} 

function* newArrGen(n) { 
    let i = 1; 
    while (i < n) yield i++; 
} 

function fiveArr(iter) { 
    const res = []; 
    for (const item of iter) { 
        if (item % 5 == 0) res.push(item); 
        else if (res.length == 2) break; 
    } 
	return res; 
} 
console.log(fiveArr(newArr(100))); 
console.log(fiveArr(newArrGen(100)));

fiveArr(newArr(100))

이 함수는 newArr이 즉시 배열을 만들어내고 1~99까지 만들어진 배열을 리턴해서 fiveArr함수를 수행하게 된다. 즉 fiveArr([1,2,3,...97,98,99])가 된다는 것이다.

fiveArr(newArrGen(100))

이 함수는 newArrGen이 interator 만 만들어 내고 fiveArr 함수에서 필요할 때 이터레이터에서 평가된 값을 사용한다.

위의 두 함수의 시간은 배열의 크기가 크면 클 수록 비약적으로 newArrGen 함수가 짧아지며 이는 즉시 평가를 하는 일반 함수와 달리 지연 평가를 하는 generator가 확실히 빠르게 동작하는 것을 볼 수 있다.

참고:

https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Iterators_and_Generators
https://bbaktaeho-95.tistory.com/80

profile
프론트 엔드 개발자입니다

0개의 댓글