Search

이터레이터와 제너레이터

개요

ES6에서 추가된 이터레이터(iterator)와 제너레이터(generator)를 많이 들어 보았는데 어떻게 쓸 수 있는지 알아보도록 하겠습니다.

이터레이터

이터러블 객체의 Symbol.iterator 메서드를 호출하면 반환되는 이터레이터는 반복을 위해 설계된 인터페이스 객체이며 {value, done}을 가지며 next의 메서드를 가지고 있습니다.

순차적 접근

for... of은 이터레이터 객체의 done 값이 true가 될 때까지 반복하며 value을 출력해 주는 방식입니다.
const arr = [1, 2, 3]; for (const a of arr) console.log(a); // 1 2 3 // 인덱스 방식으로 접근하지 않기 때문에 set, map에iter.next(); // 1서도 사용가능 const set = new Set([1, 2, 3]); for (const a of set) console.log(a); // 1 2 3 const map = new Map([ ['a', 1], ['b', 2], ['c', 3], ]); for (const a of map.keys()) console.log(a); // a b c for (const a of map.values()) console.log(a); // 1 2 3 for (const a of map.entries()) console.log(a); // ['a', 1] ['b', 2] ['c', 3]
JavaScript

메서드 호출

배열의 인덱스를 순회하는 것이 아닌 이터레이터의 next 메서드를 이용하는 것이기 때문에 이런 식으로도 사용이 가능합니다.
const arr = [1, 2, 3]; const iter = arr[Symbol.iterator](); // Symbol.iterator을 호출하여 반환된 이터레이터를 할당 iter.next(); // {value: 1, done: false}; iter.next(); // {value: 2, done: false}; iter.next(); // {value: 3, done: false}; iter.next(); // {value: undefined, done: true}; iter.next(); // {value: undefined, done: true}; iter.next(); // {value: undefined, done: true};
JavaScript

커스텀 이터레이터

이터레이터만 있다면 for.. of을 사용할 수 있는 특징을 이용하여 임의의 이터레이터를 작성하는 것도 가능합니다.
const iterable = { [Symbol.iterator]() { // 호출할수 있는 이터레이터 메서드 작성 let i = 3; return { next() { // next 메서드 작성 return i == 0 ? { vlaue: undefined, done: true } : { value: i--, done: false }; }, [Symbol.iterator]() { // next 호출 후에도 자기 자신을 반환하도록 return this; }, }; }, }; for (const a of iterable) console.log(a); // 3 2 1
JavaScript

제너레이터

위의 방식으로 커스텀 이터레이터를 만들 수도 있지만 제너레이터를 이용한다면 보다 쉽게 작성할 수 있습니다.
function* iterable(i = 0) { while (true) { yield i++; if (i > 100) return undefined; } } const iter = iterable(); iter.next(); // {value: 0, done: false}; iter.next(); // {value: 1, done: false}; iter.next(); // {value: 2, done: false}; const iter2 = iterable(10); // 제너레이터에 매개변수 전달 iter2.next(); // {value: 10, done: false}; iter2.next(); // {value: 11, done: false}; iter2.next(); // {value: 12, done: false}; for (const a of iter) { // 이터레이터가 존재하기 때문에 for of 문도 사용이 가능합니다. console.log(a); // 3 4 5 .... 100 }
JavaScript
제너레이터는 function\* 의 이름으로 함수를 생성하면 됩니다. 그리고 일반 function 이였다면 무한히 돌아가는 while으로 스크립트가 멈추었겠지만, yield라는 키워드로 독특하게 함수가 실행 되게 됩니다.
제너레이트 함수의 yield는 호출을 할 때마다 해당하는 지점에서 작동을 중지하고 변수를 기억합니다. 또한 return 통해서 종료 시점을 제어할 수도 있습니다.

참고