이터러블


 이터레이션 프로토콜

ES6에서 도입되었고, 순회 가능한 데이터 콜렉션을 만들기 위해 ECMAScript 사양에 정의하여 미리 약속한 규칙 
ES6에서는 순회 가능한 데이터 콜렉션을 이터레이션 프로토콜을 준수하는 이터러블로 통일하여 for ...of 문, 스프레드 문법, 배열 디스트럭처링 할당의 대상으로 사용할 수 있도록 일원화했다. 

 

이터러블 프로포콜 ( Iterable protocol ) 

A. Well-known Symbo인 Symbol.iterator를 프로퍼티 키로 사용한 메소드를 직접 구현 or 

B. 프로토타입 체인을 통해 상속 받은 Symbol.iterator 메소드를 호출하면 이터레이터 프로토콜을 준수한 이터레이터를 반환한다.

위 둘중에 한경우를 통해 이터레이터를 반환하는 규약을 이터러블 프로토콜이라고 한다. 이를 규약을 준수한 객체를 이터러블이라 하는데, 이터러블을 for ... of 문으로 순회할 수 있으며, 스프레드 문법과 배열 디스트럭처링 할당의 대상이 될 수 있다.

 

이터레이터 프로토콜 ( Iterator Protocol ) 

1. 이터러블의 Symbol.iterator 메소드를 호출하면, 이터레이터 프로토콜을 준수한 이터레이터를 반환한다. 

2. next 메소드를 소유하며 next 메소드를 호출하면 이터러블을 순회한다.

3. value와 done 프로퍼티를 갖는 result 객체 반환한다. 

4. done 프로퍼티는 이터러블의 순회 완료 여부를 나타낸다. 

 

이러한 규약을 이터레이터 프로토콜이라고 하며, 이터레이터 프로토콜을 준수한 객체를 이터레이터라 한다.  이터레이터는 이터러블의 요소를 탐색하기 위한 포인터 역할을 한다. 

 


빌트인 이터러블

자바스크립트는 이터레이션 프로토콜을 준수한 객체인 빌트인 이터러블을 제공한다. 

빌트인 이터러블  Symbol.iterator 메소드
Array Array.prototype[Symbol.iterator]
String String.prototype[Symbol.iterator]
Map Map.prototype[Symbol.iterator]
Set Set.prototype[Symbol.iterator]
TypedArray TypedArray.prototype[Symbol.iterator]
arguments arguments.prototype[Symbol.iterator]
DOM Collection HTMLCollection.prototype[Symbol.iterator]

 

 

유사 배열 객체에는 Symbol.iterator 메소드가 없기때문에 for ... of 문으로 순회할 수 없다. 

Array.from 메소드는 유사 배열 객체 또는 이터러블을 인수로 전달받아 배열로 변환하여 반환한다. 

// 유사 배열 객체
const arrayLike = {
  0: 1,
  1: 2,
  2: 3,
  length: 3
};

// Array.from은 유사 배열 객체 또는 이터러블을 배열로 변환한다
const arr = Array.from(arrayLike);
console.log(arr); // [1, 2, 3]

이터러레이션 프로토콜 필요성 

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

 

 

참고 영상

https://www.youtube.com/watch?v=Giam9zjd11w&list=PLEOnZ6GeucBW11uFNvzxToKym9Zv74hxh&index=19 

 

 

후기

- 평소에 for ...of, 스프레드 문법, 디스트럭쳐링이 되고 안되는 애들이 왜 안되었던건지 알게되었던거 같ㅇ...  

- 이미 for ...of 나 forEach, map같은 메소들도 이미 안에서 [Symbol.iterator]같은걸 돌리고 있던 거였다.. 

- next()를 통해 내가 원하는 때에 iteration을 멈출수 있다.  아래 피보나치 수열을 구현하는 사용자 정의 이터러블을 디버깅하며

   찍어보자... 

const fibonacciFunc = function (max) {
  let [pre, cur] = [0, 1];
  
  return {
    [Symbol.iterator]() {
      return {
        next() {
          [pre, cur] = [cur, pre + cur];
          return { value: cur, done: cur >= max };
        }
      };
    }
  };
};
for (const num of fibonacciFunc(10)) {
  console.log(num); // 1 2 3 5 8
}