(12장) 이터레이터와 제너레이터 [자바스크립트 완벽 가이드 7판]

iberis2·2023년 2월 14일
0

이터레이터와 제너레이터

Chapter12. 요약

이터레이터

  • for(요소 of 객체) 루프와 ...분해 연산자는 이터러블 객체 와 함께 사용할 수 있습니다.
  • 이터러블 객체를 반환하는, 심벌 이름 [Symbol.iterator] 메서드를 가진 객체는 이터러블입니다.
  • 이터레이터 객체에는 순회 결과 객체를 반환하는 next( ) 메서드가 있습니다.
  • 순회 결과 객체에는 다음 순회 값이 있으면 그 값을 보유하는 value 프로퍼티가 있습니다. {value: 이터레이터 값, done: false }
    • 순회가 완료됐다면 결과 객체에는 값이 true인 done 프로퍼티가 반드시 있어야 합니다. {value: undefined, done: true}
  • 순회 결과 객체를 반환하는 next() 메서드가 포함된 객체를 반환하는 [Symbol.iterator]() 메서드를 정의해 직접 이터러블 객체를 만들 수 있습니다.
    • 이터레이터 인자를 받아 이터레이터 값을 반환하는 함수 역시 만들 수 있습니다.

제너레이터

  • function이 아니라 function*으로 정의 된 제너레이터 함수로도 이터레이터를 만들 수 있습니다.
  • 제너레이터 함수를 호출하면 함수 바디가 즉시 실행되지는 않으며 반환 값은 이터러블인 이터레이터 객체입니다.
    • 이터레이터의 next() 메서드를 호출할 때마다 제너레이터 함수의 다른 코드 덩어리가 실행됩니다.
  • 제너레이터 함수는 yield 연산자를 사용해 이터레이터가 반환할 값을 지정할 수 있습니다.
    • 제너레이터 함수는 next( ) 를 호출할 때마다 다음 yield 표현식을 만날 때까지 실행됩니다.
    • 이터레이터가 반환하는 값은 yield 표현식의 값입니다.
    • yield 표현식이 더 없으면 제너레이터 함수는 실행을 종료하고 순회도 완료됩니다.
      〖자바스크립트 완벽 가이드〗 - 408 ~ 409p

📕 Interation Interface

Iteration Interface는 다음 3가지로 이루어져 있다.

이터러블(Iterable) 객체 : 배열, 세트, 맵과 같은 순회할 수 있는 타입의 객체

  • 이터레이터 객체를 반환하는 Symbol.iterator( ) 메서드 를 가지고 있다.


이터레이터(Iterator) 객체 : 순회를 수행하는 객체 자체

  • next( ) 메서드를 가지고 있다.
  • next 메서드는 이터레이션 결과(Iterator Result) 객체를 반환한다.
  • 이터레이션 결과 객체는 valuedone 프로퍼티를 가지고 있다.


이터레이션 결과(Iterator Result) 객체 : 각 순회 단계의 결과를 담은 객체

  • valuedone 프로퍼티가 있다.
    • iterator가 끝에 도달하지 않았다면, done: false이고, value는 이용 가능하다.
    • iterator가 끝에 도달했다면 done: true 이고, value는 iterator의 반환값이다.
/* 배열도 이터러블이다. */
const arr = [1, 2, 3];
const i = arr[Symbol.iterator]();

i.next(); // { value: 1, done: false }
i.next(); // { value: 2, done: false }
i.next(); // { value: 3, done: false }
i.next(); // { value: undefined, done: true }

배열, 형식화 배열, 문자열, Set과 Map 객체는 모두 이터러블이다.

  • ...스프레드 연산자를 사용할 수 있다.
  • for of 루프로 순회할 수 있다.
/* 이터러블로 for 반복문 표현하기 */

let iterable = [1];
let iterator = iterable[Symbol.iterator](); // 이터레이터 객체 반환

// 이터러블 객체를 순회하는 for 루프 문
for(let result = iterator.next(); // 초기값
    !result.done; // done 프로퍼티 값이 true가 되기 전까지
   result = iterator.next()){ // 다음 순회 호출
	console.log(result.value); // 1
  	console.log(result.done); // false
}

🖍 이터러블 객체 만들기

이름이 Symbol.iterator 인 메서드를 가지고 있어야하며,
이터레이터 객체를 반환해야 한다.

이터레이터 객체는 next() 메서드를 가지고 있어야 한다.

next() 메서드는 반드시 value 프로퍼티done: false(또는 true) 프로퍼티를 가지고 있는 이터레이션 결과(Iterator Result) 객체를 반환해야 한다.

📕 제너레이터

// 값을 미리 만들어두지 않고, next()로 호출될 때마다 실행한다.
function* fn(){
  let index = 0;
  while(true){
    yield index++;
  }
}

const a = fn();

a.next(); // {value: 2, done: false}
a.next(); // {value: 3, done: false}
a.next(); // {value: 3, done: false}

함수를 호출해도 while(true)문이 무한 반복되지 않고,
next()로 값을 불러올 때만 실행한다.

🖍 next( ) 메서드

function* fn() {
  console.log(1);
  yield 1;
  console.log(2);
  console.log(3);
  yield 2;
  return "finish";
}

const a = fn();

a // fn {<suspended>} 
/* 함수 객체만 반환되고 함수 본문은 실행되지 않았다. */

a.next(); // 1  /* console.log에서 반환된 값 */
// {value: 1, done: false} /* yield에서 반환된 값*/

a.next(); // 2 
// 3
// {value: 2, done: false} 

a.next(); // {value: 'finish', done: true}

/* done: true 이후 더 호출해도 더이상 yield값이 없으므로 value는 undefined이다.*/
a.next(); // {value: undefined, done: true}

next 메서드로 가장 가까운 yield 값을 호출하고 다음 next가 호출될 때까지 함수의 실행을 멈출 수 있다.

function* fn() {
  const num1 = yield "첫 번째 숫자 입력"; // ❶ num1에 할당 전 yield 에서 멈춤
  console.log(num1);

  const num2 = yield "두 번째 숫자 입력"; // ❷ : ❶ 이후로 실행 후 num2 할당 전 yield에서 멈춤 
  console.log(num2);

  return num1 + num2; // ❸ : ❷ 이후로 실행 후 종료 
}

const j = fn();

j.next(); /* ❶ */
// {value: '첫 번째 숫자 입력', done: false}


j.next(7); /* ❷ num1에 7 할당 */
// 7  ← num1 콘솔 출력
// {value: '두 번째 숫자 입력', done: false}


j.next(9); /* ❸ num2에 9 할당해서 num1 + num2 = 16 리턴 */
// 9   ← num2 콘솔 출력
// {value: 16, done: true}

next() 메서드에 아규먼트를 전달해서 value 값을 입력받을 수도 있다.

🖍 return( ) 메서드

function* fn() {
  console.log(1);
  yield 1;
  console.log(2);
  console.log(3);
  yield 2;
  console.log(4);
  yield 3;
  return "finish";
}

const a = fn();

a.next(); // 1
// {value: 1, done: false}

/* 호출 즉시 함수 실행이 종료된다. */
a.return('END'); // {value: 'END', done: true}

a.next(); // {value: undefined, done: true}

return() 메서드를 호출하는 즉시 {done: true} 가 되며, 그 이후 next() 메서드를 실행해도 {value: undefined, done: true} 가 리턴된다.

🖍 throw( ) 메서드

function* fn() {
  try{
  console.log(1);
  yield 1;
  console.log(2);
  console.log(3);
  yield 2;
  console.log(4);
  yield 3;
  return "finish";
  } catch(err){
  	console.log(err);
  }
}

const a = fn();

a.next(); // 1
// {value: 1, done: false}

/* Error를 처리 후 함수가 종료된다.*/
a.throw(new Error('error')); // Error: error

a.next(); // {value: undefined, done: true}

호출 즉시 에러 처리 후 {done: true} 가 된다.

profile
React, Next.js, TypeScript 로 개발 중인 프론트엔드 개발자

0개의 댓글