본문 바로가기

TIL

JS. Iterable과 Iterator

그냥 지나치면서 잠깐잠깐 봤던 개념들 언젠가 한번 정리하려고 했다. 그게 바로 투데이. 

우선 이 개념을 접했을 때 내가 아는 느낌으로는 반복할 수 있는 객체들을 이터러블 하다고 하는 거 아니야?라고만 생각했다. 근데 뭔가 정의스럽지 않으니 멋진 말로 다시 한번 정의해보자 자바스크립트 deepDive라는 책에서는 다음과 같이 이야기한다.

ES6에서 도입된 이터레이션 프로토콜(iteration protocol)은 데이터 컬렉션을 순회하기 위한 프로토콜(미리 약속된 규칙)이다. 이터레이션 프로토콜을 준수한 객체는 for…of 문으로 순회할 수 있고 Spread 문법의 피연산자가 될 수 있다.
이터레이션 프로토콜에는 이터러블 프로토콜(iterable protocol)과 이터레이터 프로토콜(iterator protocol)이 있다.

그리고 이터러블 정의

이터러블 프로토콜을 준수한 객체를 이터러블이라 한다. 이터러블은 Symbol.iterator 메서드를 구현하거나 프로토타입 체인에 의해 상속한 객체를 말한다. Symbol.iterator 메서드는 이터레이터를 반환한다. 이터러블은 for…of 문에서 순회할 수 있으며 Spread 문법의 대상으로 사용할 수 있다.
배열은 Symbol.iterator 메서드를 소유한다. 따라서 배열은 이터러블 프로토콜을 준수한 이 트러블이다.

결론적으로 Symbol.iterator를 소유하면 iterable 한 객체라 봐도 될 거 같다. 그리고 저 메서드가 return 하는 게 Iterator. 끝. 

은 아니고 좀 더 자세히 보자 , 이터레이터는 next라는 메서드를 갖는데 각 요소를 순회하기 위한 포인터 같은 역할을 한다고 보면 좋다. next 할 때마다 자동으로 다음 값을 가져온다 배열을 예를 들면 원소들을 하나씩 출력해준다. 너무 좋다. 사실 뭐가 좋은지 모르겠다. 그냥 말 나온 김에 이렇게 하면 좋은 점을 먼저 이야기해야겠다. deepdive 책을 보게 되면 이터레이션 프로토콜의 필요성에 대해 이야기하는데 다음과 같다.

이터러블은 데이터 공급자(Data provider)의 역할을 한다.
만약 이처럼 다양한 데이터 소스가 각자의 순회 방식을 갖는다면 데이터 소비자는 다양한 데이터 소스의 순회 방식을 모두 지원해야 한다. 이는 효율적이지 않다. 하지만 다양한 데이터 소스가 이터레이션 프로토콜을 준수하도록 규정하면 데이터 소비자는 이터레이션 프로토콜만을 지원하도록 구현하면 된다.
즉, 이터레이션 프로토콜은 다양한 데이터 소스가 하나의 순회 방식을 갖도록 규정하여 데이터 소비자가 효율적으로 다양한 데이터 소스를 사용할 수 있도록 데이터 소비자와 데이터 소스를 연결하는 인터페이스의 역할을 한다.

그니까 각 공급자마다 다르게 만들면 또 소비하는 사람도 다르게 해야 되니까 그러지 말고 통일해서 쓰자 뭐 이런 거 같다. 

말 나온 김에 특징 하나 더 이야기하자면 이터러블은 Lazy evaluation(지연 평가)를 통해 값을 생성한다고 한다. 지연 평가라 그러면 안 와닿으니까 Lazy evaluation으로 새겨두자. 아까 위에서 말한 next 할 때 그때 데이터가 생성된다 그전에는 안 만들어짐. 그래서 Lazy evaluation을 쓰면 성능이 더 좋아진다고 하는데 자세한 건 밑에 링크 들어가서 보면 좋겠다.

또 iterable 한 객체를 만드는 방법들도 자세한건 밑에 링크 가보자.

그중에 좀 적어보고 싶은 건 iterable 이면서 iteration 객체를 생성하는 함수 형태로 만드는 방법인데 Symbol.iterator return 값으로 this를 넘기면 된다. 자세한 코드는 밑에.

// 이터러블이면서 이터레이터인 객체를 반환하는 함수
const fibonacciFunc = function (max) {
  let [pre, cur] = [0, 1];

  // Symbol.iterator 메소드와 next 메소드를 소유한
  // 이터러블이면서 이터레이터인 객체를 반환
  return {
    // Symbol.iterator 메소드
    [Symbol.iterator]() {
      return this;
    },
    // next 메소드는 이터레이터 리절트 객체를 반환
    next() {
      [pre, cur] = [cur, pre + cur];
      return {
        value: cur,
        done: cur >= max
      };
    }
  };
};

// iter는 이터러블이면서 이터레이터이다.
let iter = fibonacciFunc(10);

// iter는 이터레이터이다.
console.log(iter.next()); // {value: 1, done: false}
console.log(iter.next()); // {value: 2, done: false}
console.log(iter.next()); // {value: 3, done: false}
console.log(iter.next()); // {value: 5, done: false}
console.log(iter.next()); // {value: 8, done: false}
console.log(iter.next()); // {value: 13, done: true}

iter = fibonacciFunc(10);

// iter는 이터러블이다.
for (const num of iter) {
  console.log(num); // 1 2 3 5 8
}

 

그리고 이러한 형식을 well-formed Iterable이라고 하는데, 이걸 또 쉽게 만드는 방식이 Generator 함수라고 하는 방식이 있다. 이건 나중에 정리하겠다.

그래서 결론은 이터러블은 Symbol.Iterator를 가지고 , 이터레이터는 next메서드를 가지며 이 트러블을 순회하며 정해둔 조건에 맞게 결과를 반환하는 객체다. 이걸 쓰면 복잡하게 따로 만들 필요 없이 통일된 인터페이스를 제공해준다.

 

참고: https://poiemaweb.com/es6-iteration-for-of#4-%EC%9D%B4%ED%84%B0%EB%A0%88%EC%9D%B4%EC%85%98-%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C%EC%9D%98-%ED%95%84%EC%9A%94%EC%84%B1

 

Iteration & for...of | PoiemaWeb

ES6에서 도입된 이터레이션 프로토콜(iteration protocol)은 데이터 컬렉션을 순회하기 위한 프로토콜(미리 약속된 규칙)이다. 이 프로토콜을 준수한 객체는 for...of 문으로 순회할 수 있고 Spread 문법의

poiemaweb.com

https://armadillo-dev.github.io/javascript/what-is-iterable-and-iterator/

 

[Javascript] Iterable과 Iterator 이해하기

자바스크립트에서 Iterable과 Iterator이 무엇이고 어떻게 사용할 수 있는지 정리해보았다.

armadillo-dev.github.io

 

틀린 부분 혹은 가르침 부탁드립니다.

 

 

'TIL' 카테고리의 다른 글

JS. 자바스크립트 실행컨텍스트  (0) 2022.01.13
Flux 그전에 MVC  (0) 2022.01.12
CSR 과 SSR  (0) 2022.01.12
JS. 자바스크립트 히든 클래스  (0) 2022.01.11
DOM  (0) 2022.01.10