지난 포스팅에서 이터러블과 이터레이터에 대해서 살펴보았다.
또한 제너레이터라는 것을 사용하면 이터레이터를 편리하게 만들 수 있다는 것을 알게 되었다.
이번 포스팅에서는 제너레이터를 사용하여 이터레이터를 만들어보자.
- 제너레이터는 함수의 실행을 중간에 멈췄다가 재개할 수 있는 기능을 가진 함수를 말한다.
- 반복할 수 있는 이터레이터 객체를 생성한다.
제너레이터가 일반 함수와 다른 점은 함수의 실행을 제어할 수 있다는 점이다.
그렇다면 제너레이터 객체란 무엇일까?
제너레이터 함수를 호출했을 때 리턴되는 객체를 제너레이터 객체라고 한다.
여기서 객체는 이터러블이면서 동시에 이터레이터이다.
function* createIterator() {
yield 1;
yield 2;
yield 3;
}
// generator는 iterator를 반환한다.
let iterator = createIterator();
console.log(iterator.next().value); // 1
console.log(iterator.next().value); // 2
console.log(iterator.next().value); // 3
따라서 for-of
반복문을 사용해 값을 얻을 수 있다.
function* generateSequence() {
yield 1;
yield 2;
return 3;
}
let generator = generateSequence();
for(let value of generator) {
alert(value); // 1, 2
}
⚠️ 위 코드에서 3은 출력되지 않는다. 왜 그럴까?
for-of 이터레이션이 done: true일 때 마지막 value를 무시하기 때문이다. 그러므로 for-of를 사용했을 때 모든 값이 출력되길 원한다면 yield로 값을 반환해야 한다.
function* generateSequence() {
yield 1;
yield 2;
yield 3;
}
let generator = generateSequence();
for(let value of generator) {
alert(value); // 1, 2, 3
}
제너레이터를 사용하지 않고 이터레이터(객체의 반복)를 구현해보자
function createIterator(items) {
let i = 0;
return {
next: function() {
const done = (i >= items.length);
const value = !done ? items[i++] : undefined;
return {
done: done,
value: value,
};
}
};
}
const iterator = createIterator([1, 2, 3]);
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next()); // "{ value: 2, done: false }"
console.log(iterator.next()); // "{ value: 3, done: false }"
console.log(iterator.next()); // "{ value: undefined, done: true }"
제너레이터를 사용하여 이터레이터(객체의 반복)를 구현해보자.
제너레이터 문법
function*
이 필요하다.yield
키워드를 만나면 해당 지점에서 동작을 멈추며 yield 키워드 뒤에 지정된 값을 반환한다.next()
함수를 사용하여 제너레이터 함수를 호출할 수 있다.function *createIterator() {
yield 1;
yield 2;
yield 3;
}
// generator는 iterator를 반환한다.
let iterator = createIterator();
console.log(iterator.next().value); // 1
console.log(iterator.next().value); // 2
console.log(iterator.next().value); // 3
확실히 제너레이터를 사용한 쪽이 코드의 가독성, 간결성면에서 우수하다고 할 수 있다.
function * generatorFunc(n) {
yield n;
return n + 1; // 제너레이터 종료
yield n + 2; // 동작 안함
}
const generatorObj = generatorFunc(1);
console.log(generatorObj.next());
console.log(generatorObj.next());
console.log(generatorObj.next());
실제 예제
// (1) 제너레이터 함수 안에서 쓸 addCoffee 함수 선언
var addCoffee = function (prevName, name) {
setTimeout(function () {
coffeeMaker.next(prevName ? prevName + ', ' + name : name);
}, 500);
};
// (2) 제너레이터 함수 선언
// yield 키워드로 순서 제어
var coffeeGenerator = function* () {
var espresso = yield addCoffee('', '에스프레소');
console.log(espresso);
var americano = yield addCoffee(espresso, '아메리카노');
console.log(americano);
var mocha = yield addCoffee(americano, '카페모카');
console.log(mocha);
var latte = yield addCoffee(mocha, '카페라떼');
console.log(latte);
};
// coffeeMaker는 이터레이터 객체
var coffeeMaker = coffeeGenerator();
coffeeMaker.next();