자바스크립트 이터레이터와 제네레이터

dahyeon·2023년 1월 4일
0

자바스크립트

목록 보기
5/7
post-thumbnail
post-custom-banner

이터레이터

이터레이터

이터레이터란 반복 처리가 가능한 객체를 말한다.

Symbol.iterator

반복 가능한 객체라고 하면 배열을 떠올릴 수 있지만 배열은 이터레이터가 아니다. 하지만 배열은 Symbol.iterator 메서드를 가지고 있는데, 이 메서드는 이터레이터를 반환한다.

var iter = a[Symbol.iterator]();

이터러블한 객체

Symbol.iterator 메서드를 가진 객체. for/of 문으로 순회 가능하다.

이터레이터 ≠ 이터러블한 객체

next()

이터레이터에는 next() 메서드가 있는데, 이를 호출할 때마다 이터레이터 리절트(iterator result)가 반환된다.

  • iterator result value, done 프로퍼티를 갖는 객체
    console.log(iter.next()); // -> Object { value: 5, done: false }
    • value: 꺼낸 값
    • done: 반복이 끝났는지 뜻하는 논리값

반복 가능한 객체와 for/of 문

for/of 문은 이터레이터를 반환하는 Symbol.iterator 메서드를 가지고 있는 객체를 반복 처리한다.

  • 이터레이터의 next 메서드를 순회할 때마다 매번 호출한다.

이터러블한 내장 객체의 이터레이터

이터러블한 내장 객체의 이터레이터도 이터러블하다.

🤔 Map.prototype.keys(), values()는 배열이 아닌 이터레이터 객체인데 어떻게 for/of 문으로 순회할 수 있을까?

→ 두 메서드의 결과값은 이터레이터 객체이지만 이터러블한 객체이기도 하다.

그 외 Array, String, TypedArray, Map, Set으로 생성한 객체는 반복 처리를 할 수 있고, 이들 객체로 생성한 이터레이터도 반복 처리할 수 있다.


제네레이터

제네레이터

제네레이터는 이터레이터를 값으로 반환하는 함수로, 여러 개의 값을 필요에 따라 하나씩 반환(yield)함으로써 손쉽게 데이터 스트림을 만들기 위해 사용된다.

제네레이터의 생성과 실행

제네레이터는 function* 문으로 정의해서 생성할 수 있다.

function* generateSequence() {
  yield 1;
  yield 2; 
  return 3; 
}
  • 제네레이터 함수를 호출하면 코드가 실행되지 않고, 대신 실행을 처리하는 제네레이터 객체가 반환된다.
    var iter = generateSequence();
  • 제네레이터 객체의 next() 메서드를 호출하면 가장 가까운 yield <value> 문을 만날 때까지 실행된다. 실행의 결과로 value와 함수의 코드 실행이 끝났는지 뜻하는 논리값인 done을 가진 객체를 반환한다.
    console.log(iter.next()) // -> { value: 1, done: false }
  • next()를 또 호출하면 이전에 실행이 끝난 위치에서 시작하여 처리를 재개하고, 다음 번 yield 연산자의 위치까지 실행한다.
    console.log(iter.next()) // -> { value: 1, done: false }
    console.log(iter.next()) // -> { value: 2, done: false }
    console.log(iter.next()) // -> { value: 3, done: true }
  • 제네레이터로 생성한 이터레이터는 이터러블하기 때문에 for/of 문으로 반복해서 처리할 수 있다.
    for (var v of iter) console.log(v); // 1, 2를 순서대로 표시한다.
    ❗ for/of 이터레이션은 done: true 일 때 마지막 value를 무시한다. 모든 값이 출력되길 원한다면 return이 아닌 yield로 값을 반환해야 한다.

제네레이터에 값 넘기기

next() 메서드에 값을 대입하면 제네레이터에 값을 넘길 수 있다. 넘긴 값은 일시적으로 정지하기 직전의 yield 값으로 사용된다.

function* fibonacci() {
	var fn1 = 0, fn2 = 1;
	while(true) {
		var fnew = fn1 + fn2;
		fn1 = fn2;
		fn2 = fnew;
		reset = yield fn1;
		if (reset) {
			fn1 = 0; fn2 = 1;
		}
	}
}

var iter = fibonacci();
for(var i = 0; i < 10; i++){
	console.log(iter.next().value); // 1, 1, 2, 3, 5, ... 55가 순서대로 출력된다.
}

console.log(iter.next().value); // 89
console.log(iter.next(true).value); // 1 (리셋됨!!)

위 예시에서 next() 메서드가 실행되면 fn1 값을 반환하고 일시 정지하게 된다. 만약 아무런 값도 넘기지 않을 경우 reset의 값은 undefined가 되므로 초기화가 진행되지 않고 이어서 실행된다. 반면 next(true)와 같이 넘길 경우 이전 yield 값을 받는 resettrue가 되면서 초기화가 진행된다.

반복 가능한 객체에 위임하기: yield*

yield*를 사용해서 이터러블한 객체를 지정하면 여기서 순차적으로 값을 꺼내 각각의 값에 yield를 적용한다.

function* g(){
	yield 0;
	yield* [2, 4];
	yield* "AB";
}

위 제네레이터의 반환값을 순회하면 0, 2, 4, A, B의 순서대로 출력된다.


참고자료

책 <모던 자바스크립트 입문> 이소 히로시 지음
Map.prototype.keys() - JavaScript | MDN
제너레이터

profile
https://github.com/dahyeon405
post-custom-banner

0개의 댓글