제너레이터와 이터레이터

자바스크립트에서는 어떤 값이든 이터러블이면 순회할 수 있다. 제너레이터로는 어떤 상태, 값이든 이터러블하게 만들 수 있다(다형성).

제너레이터란 이터레이터이자 이터러블을 생성하는 함수, 이터레이러를 리턴하는 함수다. 일반 함수 앞에 *를 붙여 만들 수 있다.

function *gen() {
	yield 1;
	yield 2;
	yield 3;
	return 100; // done: true일때 undefined 대신 value가 되는 값. 순회되진 않는다.
}
let iter = gen();
log(iter.next());

for (const a of gen()) // 도 가능
    console.log(a)

iter[Symbol.iterator]() == iter)의 값은 true다. 제너레이터는 잘 만들어진 이터레이터를 리턴하기 때문이다.

odds: 주어진 이터러블에서 홀수만 뽑아내기

// 무한하긴 하지만 내가 제너레이터를 평가할때만 돌아가므로 브라우저가 뻗지 않는다.
function *infinity(start=0) {
	while (true) yield start++;
}

주어진 start에서부터 무한대의 값을 담은 이터레이터를 반환하는 제너레이터 infinity는 위처럼 구현할 수 있다. 만약 제너레이터 없이 1부터 무한대의 값을 담은 배열을 만드려고 했다면 브라우저가 멈췄을 것이다. 그러나 위 코드처럼 제너레이터로 만들면 값은 무한하지만 값을 평가할때만 돌아가므로 브라우저가 뻗지 않는다.

이터러블을 순회하며 주어진 l에서 멈추는 제너레이터 limitl까지의 홀수를 담은 이터레이터를 반환하는 제너레이터 odds는 아래와 같이 구현할 수 있다.

// iter를 받아서 iter를 돌다가 l을 만나면 멈춘다.
function *limit(l, iter) {
	for (const a of iter) {
		yield a;
        if (a==l) return;
	}
}
limit(4, [1,2,3,4]);

function *odds(l) {
	for (const a of limit(l, infinity(1))) {
		if (a % 2) yield a;
	}
}

let oddIter = odds(10) // max 값

odds는 위에서 만든 limitinfinity를 활용해 구현하였다.

조합성 있는 코드 만들기

이터러블 프로토콜을 따르면 조합성 있는 코드를 작성할 수 있다. 이전 장에서 본 for…of외에도 전개 연산자, 구조 분해, 나머지 연산자 등등을 활용하기 좋다.

log([...odds(10)]) // 스프레드해 바로 배열로 만들기: [1 3 5 7 9]

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

참고: 인프런 함수형 프로그래밍과 Javascript ES6+