hmk run dev

이터레이터 & 제너레이터 본문

javascript

이터레이터 & 제너레이터

hmk run dev 2022. 4. 18. 15:35

이터레이터 

 

이터레이터는 자바스크립트뿐만 아니라 다른 언어들에도 있는 개념으로, 루프를 생각하면 이해하기 쉽습니다.

배열(array)은 대표적인 이터레이블 객체로서 이터레이터를 사용할 수 있습니다.

 

이터레이터는 단순히 루프를 수행하는 것이 아닌 현재 어디를 돌고 있는지 확인할 수 있습니다.

const arr = [1,2,3]
const it = arr.values()

위의 코드를 보면 arr에 values()를 이용해 이터레이터를 생성했습니다.

 

it를 console에 찍어보면 이처럼 이터레이터 객체가 찍힙니다!

이터레이터 객체는 next라는 메서드를 가지고 있고 next를 arr의 개수만큼 사용하면 아래와 같습니다.

next()를 호출할 때마다 그다음 값으로 넘어가며 모든 값을 돌고 나면 done이 true값으로 출력되고 value는 undefined로 출력이 됩니다!

 

 

for of 문을 이터레이터를 사용해 흉내 내보면 다음과 같다

const arr = [1,2,3]

const it = arr.values();

let i = it.next()

while(!i.done){
	console.log(i.value);
    i = it.next();
}

for (let i of number) {
	console.log(i)
}

 

위의 while문과  for of 문은 동일한 동작을 수행한다. 즉 이 트러블 오브젝트란 반복 가능한 오브젝트를 의미하여 이터레이터란 이러한 반복을 정의한 규약이라고 할 수 있다. 이 두 가지를 포함한 개념을 이터레이션 프로토콜이라 한다. 이터레이터란 프로토콜의 하나이므로 일반 오브젝트를 이터레이터 프로토콜을 적용하면 이터레이블 오브젝트로 만들 수 있다. 이때 사용되는 것이 Symbol.iterator이다.

 

이 트러블 오브젝트로 만들려면 Symbol.iterator와 value, done가 들어있는 오브젝트를 반환하는 next 메서드를 가진 객체를 반환하기만 하면 된다.

 

일반 array와 iterable 객체를 비교해보자

 

const arr = [1,2,3];
const iterableObj = arr[Symbol.iterator]()

 

둘을 콘솔을 찍어 비교해보면

 

 

이터레이터를 실용적으로 이용해보자!

 

마라톤 대회에서 들어온 순서대로 class를 통해 기록하는 코드를 짜 본다고 가정해보자 

class는 루프를 돌 수 없어 순위를 찍을 수가 없다. array에 다시 집어넣거나 값에 직접 접근해야 할까? 

이럴 때 이터레이션 프로토콜이다. 우선 Symbol.iterraor 메서드를 추가하고 value, done을 리턴하는 next 메서드를 리턴하도록 만들면 된다.

 

class Rank {
	constructor(){
    	this.ranking = [];
    }
	add(winner){
    	const rank = this.ranking.length + 1;
        this.ranking.push({ winner, rank })
    }
    
    [Symbol.iterator]() {
    	return this.ranking.values();
    }
}

 

해당 콘솔을 확인하면 순서대로 돌면서 우승자를 출력한다.

 

1st winner is John

2st winner is Lion

3st winner is Gill

4st winner is Muzi

const marathonRanking = new Rank();

marathonRanking.add("John");
marathonRanking.add("Lion");
marathonRanking.add("Gill");
marathonRanking.add("Muzi");

for (let ranking of marathonRanking){
	console.log(`${ranking.rank}st winner is ${ranking.winner}`)
}

 


제너레이터

다양한 곳에서 이터레이터를 사용할 수 있지만 아마도 이터레이터를 가장 효율적으로 사용하는 방식이 바로 제너레이터라고 할 수 있습니다.

 

제너레이터는 이터레이터를 사용해 실해을 제어하는 함수입니다.

일반적인 함수는 호출하고 나면 제어권을 함수에게 빼앗기는데요 그러나 제너레이터 함수를 이용하면 함수의 실행을 조절할 수 있습니다.

 

함수를 일시정지 하거나 다시 시작하는 등 함수의 실행을 제어할 수 있습니다.

 

제너레이터 함수는 function 키워드 뒤에 *를 붙여주고 return 외에도 yield를 사용할 수 있습니다.

 

 

간단한 카운터 함수로 예시를 살펴보자!

function* countDown() {
	yield 5;
    yield 4;
    yield 3;
    yield 2;
    yield 1;
}

const it = countDown();

 

콘솔을 찍어보면 아래와 같이 출력된다.

{value: 5, done: false}
{value: 4, done: false}
{value: 3, done: false}
{value: 2, done: false}
{value: 1, done: false}
{value: undefined, done: true}

 

next()를 이용해 함수의 실행이 순차적으로 진행되었다! 

제너레이터 함수는 제너레이터 오브젝트를 생성하는 함수로서 위의 예에서 countDown 함수는 제너레이터 함수이며 it는 제너레이터 오브젝트이다.

 

제너레이터 함수에서는 yield 키워드가 있을때 까지 실행되므로 yield 이전에 잇는 평가문들의 실행을 멈출수는 없다.

 

function* catchMe() {
  console.log("You can't catch me");
  console.log("I'm working");
  console.log("Can you catch me?");

  yield "I catch you";

  console.log("I'm not working");
}

const it = catchMe();

it.next();

 

첫번째 it.next();

두번째 it.next();

 

 

 

 

출처 

https://uzihoon.com/post/f27b7310-64e0-11ea-84dc-878832775ccf

 

UZILOG

 

uzihoon.com

 

Comments