탄탄한 기본기!

javaScript - 이터러블과 이터레이터 본문

개인 공부/JS (자바스크립트)

javaScript - 이터러블과 이터레이터

두영두영 2021. 6. 1. 15:58

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

 


1. 빌트인 이터러블

자바스크립트에는 아래와 같은 이터레이션 프로토콜을 준수한 빌트인 이터러블 객체들이 존재한다.

 

  • Array
  • String
  • Map
  • Set
  • TypedArray
  • arguments
  • DOM Collection

2. 이터러블과 이터레이터

이터러블은 이터러블 프로토콜을 준수한 객체이며, Symbol.iterator를 프로퍼티 키로 직접 메서드를 구현하거나 상속(프로토타입) 받은 객체를 말한다. 즉, 객체의 프로퍼티로 Symbol.iterator가 존재해야지 이터러블인 것이다.

const array = [1, 2, 3];

console.log(Symbol.iterator in array); // true

이터러블은 for…of 문으로 순회할 수 있으며 스프레드 문법배열 디스트럭처링 할당의 대상으로 사용할 수 있다.

 

이터레이터는 이터러블의 Symbol.iterator를 호출했을 때 반환되는 객체이다. 이 객체는 next메서드를 가지며 next메서드를 호출할 경우 반환되는 객체에는 valuedone프로퍼티가 존재해서 이터러블을 순회할 수 있다.

const array = [1, 2, 3];	// 이터러블

const iterator = array[Symbol.iterator]();	// 이터레이터

console.log('next' in iterator); // true
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 }

 

3. 유사 배열 객체

유사 배열 객체의 경우 length 프로퍼티를 가지고 있기 때문에 for문으로 순회할 수 있지만, 유사 배열 객체는 이터러블이 아닌 일반 객체이며, Symbol.iterator 메서드가 없기 때문에 for…of 문으로 순회할 수 없다.

for (const item of arrayLike) {
  console.log(item); // 1 2 3
}
// -> TypeError: arrayLike is not iterable

 

하지만 유사 배열 객체이면서 이터러블일 수도 있다. 앞서 말한 대로 Symbol.iterator메서드를 내부적으로 구현하면 되기 때문이다. 예를 들어서 arguments, NodeList, HTMLCollection의 경우에는 유사 배열 객체이면서 이터러블이다. ES6에서 이터러블이 도입되면서 유사 배열 객체인 arguments, NodeList, HTMLCollection 객체에 Symbol.iterator 메서드를 구현했기 때문이다.

4. 이터레이션 프로토콜의 필요성

순회 가능한 데이터 컬렉션을 이터레이션 프로토콜을 준수하는 이터러블로 통일하여 for…of 문, 스프레드 문법, 배열 디스트럭처링 할당의 대상으로 사용할 수 있도록 일원화할 수 있다는 점이 중요하다.

 

만약 데이터 컬렉션들이 각각 순회하는 방법이 모두 다르다면 사용자(개발자)는 그 방법들을 모두 숙지해야 할 것인데, 이터러블의 경우에는 통일된 방법으로 이터레이터를 생성해서 next메서드를 호출함으로써 데이터를 순회할 수 있다. 즉, 이터레이션 프로토콜은 데이터 순회를 위한 인터페이스를 제공한다는 점에서 중요하다.

 

그리고 아래 예시처럼 사용자가 직접  Symbol.iterator메서드를 구현해서 커스터마이징 할 수도 있기 때문에 자유도가 높기도 하다.

const fibonacci = {
  [Symbol.iterator]() {
    const max = 10;
	let [pre, cur] = [0, 1];

    // next 메서드를 소유한 이터레이터(객체)를 반환
    return {
      next() {
        [pre, cur] = [cur, pre + cur];

        return { value: cur, done: cur >= max };
      }
    };
  }
};

for (const num of fibonacci) {
  console.log(num); // 1 2 3 5 8
}

5. 무한 이터러블과 지연 평가

이터레이터의 next메서드를 통해서 value와 done을 가지고 있는 객체를 반환받기 때문에, next를 호출하기 전까지는 그다음 값을 모르는 상태이다. 그리고 이러한 특성을 이용해 무한 이터러블을 구현하고, 필요한 시점에 그때마다 값을 평가해 얻는 방식을 사용할 수 있다.

const fibonacciFunc = function () {
  let [pre, cur] = [0, 1];

  return {
    [Symbol.iterator]() { return this; },
    next() {
      [pre, cur] = [cur, pre + cur];
      // 무한을 구현해야 하므로 done 프로퍼티를 생략
      return { value: cur };
    }
  };
};

for (const num of fibonacciFunc()) {
  if (num > 10000) break;
  console.log(num); // 1 2 3 5 8...4181 6765
}

 

'개인 공부 > JS (자바스크립트)' 카테고리의 다른 글

DOM(Document Object Model) - HTMLCollection과 NodeList  (0) 2021.06.06
javaScript - Set과 Map  (0) 2021.06.03
javaScript - Symbol 타입  (0) 2021.06.01
Node.js와 Jest 실습  (0) 2021.06.01
javaScript - String  (0) 2021.05.30
Comments