Notice
Recent Posts
Recent Comments
관리 메뉴

즐겁게, 코드

이터레이터와 이터러블 본문

💬 언어/Javascript

이터레이터와 이터러블

Chamming2 2021. 2. 4. 15:05

ES6부터는 for...of 라는 새로운 문법으로 배열을 순회할 수 있게 되었습니다. 

const student = ["찬민", "연주"];

for (let i of student) {
  console.log(i); 
}
// 찬민
// 연주

이렇게 for...of 등 "반복 가능" 한 동작을 수행할 수 있는 객체*를 반복 가능한(iterable)한 객체 라고 부르는데요, 오늘은 이터러블한 객체를 생성하는 방법을 소개하려 합니다.

(* 배열 역시 Array 객체이므로 객체 라는 표현을 사용했습니다.)

이터레이터 프로토콜 / 이터러블 프로토콜

이터러블한 객체를 만들기 전에 먼저 이터러블과 이터레이터를 정확히 구분해야만 합니다.

둘을 구분하기 위한 규칙 역시 아래와 같이 존재합니다.

 

이터레이터 프로토콜

- 반복의 종결여부를 표현하는 donevalue 프로퍼티를 갖는 객체를 리턴하는 next() 메서드를 갖는 객체를 이터레이터라 한다.

next() 메서드를 통해 컬렉션을 순회하면서 다음 시퀀스를 진행한다.

 

이터러블 프로토콜

- 이터레이터 프로토콜을 만족하는 [Symbol.iterator] 프로퍼티를 갖는 객체를 이터러블 객체라 한다.

- for...of 문 등을 통해 순회할 수 있으며 내장 객체인 Array, Map, Set, String 등이 있다.

 

두 규칙에 대한 보다 구체적인 명세나 예시는 MDN 링크 를 참조할 수 있습니다.

이터레이터

먼저 이터레이터를 구현해 보겠습니다.

위에서 소개한 이터레이터 프로토콜을 토대로 next() 메서드를 구현했고, 이제 studentList 객체는 next() 메서드를 활용해 데이터를 순회할 수 있는 이터레이터라 할 수 있습니다.

const studentList = {
  students: ["찬민", "희진", "수형"],
  index: 0,
  next() {
    if (this.students.length !== this.index) {
      return {
        done: false,
        value: this.students[this.index++],
      };
    } else {
      return {
        done: true,
      };
    }
  },
};

console.log(studentList.next()); // { done: false, value: '찬민' }
console.log(studentList.next()); // { done: false, value: '희진' }
console.log(studentList.next()); // { done: false, value: '수형' }
console.log(studentList.next()); // { done: true }

다음은 이터러블을 구현해 보겠습니다.

이터러블 프로토콜대로 이터러블 객체를 구현한 결과입니다.

const studentList = {
  [Symbol.iterator]: () => {
    let index = 0;
    const students = ["찬민", "희진", "수형"];
    return {
      next() {
        return index !== students.length
          ? {
              done: false,
              value: students[index++],
            }
          : {
              done: true,
            };
      },
    };
  },
};

for (const student of studentList) {
  console.log(student); // 찬민 희진 수형
}

뭘 만든 것인지 감이 오지 않는다면 next() 메서드가 리턴하는 객체의 value 프로퍼티를 result 라는 이름으로 바꿔 보세요.

그럼 donevalue를 리턴하기로 한 이터레이터 프로토콜에 어긋나 객체를 순회하지 못하는 모습을 확인할 수 있습니다.

const studentList = {
  [Symbol.iterator]: () => {
    let index = 0;
    const students = ["찬민", "희진", "수형"];
    return {
      next() {
        return index !== students.length
          ? {
              done: false,
              // 이터레이터 프로토콜 위반
              result: students[index++],
            }
          : {
              done: true,
            };
      },
    };
  },
};

for (const student of studentList) {
  console.log(student); // undefined undefined undefined
}

지금은 next() 라는 메서드가 done과 value를 갖는 객체를 반환하도록 직접 구현했지만, 다음에 다룰 제너레이터 문법을 활용하면 이터러블을 보다 쉽게 구현할 수 있습니다.

참고

- iteration protocol, MDN

- for...of, MDN

반응형
Comments
소소한 팁 : 광고를 눌러주시면, 제가 뮤지컬을 마음껏 보러다닐 수 있어요!
와!! 바로 눌러야겠네요! 😆