Javascript | 이터레이션(Iteration) & 제너레이터(Generator)

yuni·2022년 11월 9일
0

javascript

목록 보기
14/16
post-thumbnail

❔ 이터레이션 프로토콜(Iteration Protocal) ❔

⇨ 이터레이션 프로토콜(Iteration Protocal)는 데이터 컬렉션을 반복, 순회 가능(iterable)하도록 하는 프로토콜(미리 약속된 규칙)이다.

자바스크립트에서 이터레이션 프로토콜을 따르는 객체는 연산자 for...ofspread를 사용가능하다.

배열은 대표적인 이터러블이다. 배열 외에도 다수의 내장 객체가 반복 가능하다.
문자열(Stiring), Map, Set 역시 이터러블의 예이다.

이터레이션 프로토콜에는 이터러블 프로토콜(iterable protocol)과 이터레이터 프로토콜(iterator protocol)이 있다.

👍 필요성

  • 데이터 소비자(Data consumer)인 for…of 문, spread 문법 등 다양한 데이터 소스(Array, Srting, set, Mep 등)를 사용한다. 이터러블은 데이터 공급자의 역할을 한다.

  • 이터레이션 프로토콜은 다양한 데이터 소스가 하나의 순회 방식을 갖도록 규정하여 데이터 소비자가 다양한 데이터 소스를 사용할 수 있도록 데이터 소비자와 데이터 소스를 연결하는 인터페이스의 역할을 한다.

🔁 이터러블(Iterable) : 순회 가능한

⇒ 이터러블 프로토콜(iterable protocol)을 준수한 객체를 이터러블이라 한다. 이터러블은 Symbol.iterator 메소드를 구현하거나 프로토타입 체인에 의해 상속한 객체를 말한다. Symbol.iterator 메소드는 이터레이터(iterator)를 반환한다.

const array = [1, 2, 3];

// 배열은 Symbol.iterator 메소드를 소유한다.
// 따라서 배열은 이터러블 프로토콜을 준수한 이터러블이다.
console.log(Symbol.iterator in array); // true

// 이터러블 프로토콜을 준수한 배열은 for...of 문에서 순회 가능하다.
for (const item of array) {
  console.log(item);
}
//1
//2
//3

⇊ 일반객체는 Symbol.iterator 메소드를 소유하지 않기 때문에 이터러블이 아니다. 따라서 for...of 또는 spread를 사용하면 typeerror가 된다.

const obj = { a: 1, b: 2 };

// 일반 객체는 Symbol.iterator 메소드를 소유하지 않는다.
// 따라서 일반 객체는 이터러블 프로토콜을 준수한 이터러블이 아니다.
console.log(Symbol.iterator in obj); // false

// 이터러블이 아닌 일반 객체는 for...of 문에서 순회할 수 없다.
for (const item of obj) {
  console.log(p);
}
// TypeError: obj is not iterable

🔁 이터레이터(Iterator) : 포인터, 반복자

⇒ 이터레이터 프로토콜은 next 메소드를 소유하며 next 메소드를 호출하면 이터러블을 순회하며 value, done 프로퍼티를 갖는 이터레이터 리절트(iterator result) 객체를 반환하는 것이다. 이 규약을 준수한 객체가 이터레이터이다.

이터레이터의 next 메소드는 이터러블의 각 요소를 순회하기 위한 포인터의 역할을 한다. next 메소드를 호출하면 이터러블을 순차적으로 한 단계씩 순회하며 이터레이터 리절트 객체를 반환한다. 이터레이터 리절트 객체의 value 프로퍼티는 현재 순회 중인 이터러블의 값을 반환하고 done 프로퍼티는 이터러블의 순회 완료 여부를 반환한다.

const array = [1, 2, 3];

// 이터레이터 프로토콜을 준수한 이터레이터는 next 메소드를 갖는다.
console.log('next' in iterator); // true

// 이터레이터의 next 메소드를 호출하면 
// value, done 프로퍼티를 갖는 이터레이터 리절트 객체를 반환한다.
// value : 현재의 순회 값 , done: 순회의 완료 유무
const iterator = array.values();
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 }

❔ 제너레이터(Generator) : 생성기 ❔

⇨ 제너레이터(Generator) 함수는 이터러블을 생성하는 함수이다. 이터레이션 프로토콜을 준수해 이터러블을 생성하는 방식보다 간편하게 이터러블을 구현할 수 있으며, 비동기 처리에 유용하게 사용된다.

제너레이터 함수는 일반 함수와 같이 함수의 코드 블록을 한 번에 실행하지 않고 함수 코드 블록의 실행을 일시 중지했다가 필요한 시점에 재시작할 수 있는 특수한 함수이다.
* yield : 이 키워드는 제너레이터 함수를 중지하거나 재개하는데 사용된다. 다음 next를 호출할때까지 기다렸다가 호출할때 다음 코드를 실행하며 순회한다. 즉, 사용자가 제어권을 가진다.

제너레이터 함수를 호출하면 제너레이터를 반환한다. 이 제너레이터는 이터러블(iterable)이면서 동시에 이터레이터(iterator)인 객체이다.

제너레이터 함수는 function* 키워드로 선언한다. 그리고 하나 이상의 yield 문을 포함한다.

// 이터레이션: 무한 이터러블을 생성하는 함수
const infinityByIteration = function () {
  let i = 0; // 자유 변수
  return {
    [Symbol.iterator]() { return this; },
    next() {
      return { value: ++i };
    }
  };
};

for (const n of infinityByIteration()) {
  if (n > 5) break;
  console.log(n); // 1 2 3 4 5
}

// 제너레이터: 무한 이터러블을 생성하는  함수
function* infinityByGenerator() {
  let i = 0;
  while (true) { yield ++i; }
}

for (const n of infinityByGenerator()) {
  if (n > 5) break;
  console.log(n); // 1 2 3 4 5
}

참고 및 출처
Iteration_protocols - MDN
iterable 객체 - javascript.info
Iteration & for...of - poiemaweb
Generator - poiemaweb
yield - MDN

profile
˗ˋˏϟˎˊ˗ 개발 지식 쌓기

0개의 댓글