이터레이션 프로토콜

  • ES6에서 도입된 이터레이션 프로토콜은 데이터 컬렉션을 순회하기 위한 프로토콜(=미리 약속된 규칙)
  • 이터레이션 프로토콜을 준수한 객체
    : for ...of문
    : Spread 문법의 피연산자
  • 이터러블 프로토콜 , 이터레이션 프로토콜 두 가지가 있다.

💡 이터러블

  • [Symbol.iterator]();
  • 순회 가능한 자료구조
    : 배열,문자열,arguments객체,프로토타입체인에 의해 상속된 객체
  • symbol.iterator 메소드 소유 --> 이터레이터 반환
  • 일반객체는 이터레이션 프로토콜을 준수(Symbol.iterator메소드 소유)하지 않기 때문에 이터러블이 아니다.단, 커스텀 이터러블에서는 사용 가능
  • for ...of문에서 순회 가능
  • Spread 문법의 대상으로 사용 가능
// 배열은 Symbol.iterator 메소드를 소유,따라서 배열은 이터러블 프로토콜을 준수한 이터러블이다.
const array = [1, 2, 3];
console.log(Symbol.iterator in array); // true

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

// 일반 객체는 Symbol.iterator 메소드를 소유하지않음, 따라서 일반 객체는 이터러블 프로토콜을 준수한 이터러블이 아니다.
const obj = { a: 1, b: 2 };
console.log(Symbol.iterator in obj); // false

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

💡 이터레이터

  • next() : 이터러블을 순회하며 value,done 프로퍼티 를 갖는 이터레이터 리절트(result)객체를 반환
  • next()메소드는 이터러블의 각 요소를 순회하기 위한 포인터 역할
    : 호출하면 이터러블을 순차적으로 한 단계씩 순회하며 이터레이터 리절트 객체를 반환
  • result.value : 현재 순회 중인 이터러블 값 반환
  • result.done : 이터러블의 순회 완료 여부 반환
// 배열은 이터러블 프로토콜을 준수한 이터러블이다.
const array = [1, 2, 3];

// Symbol.iterator 메소드는 이터레이터를 반환한다.
const iterator = array[Symbol.iterator]();

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

// 이터레이터의 next 메소드를 호출하면 value, done 프로퍼티를 갖는 이터레이터 리절트 객체를 반환한다.
// next 메소드를 호출할 때 마다 이터러블을 순회하며 이터레이터 리절트 객체를 한단계씩 반환한다.
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} // 순회완료

빌트인 이터러블

: 이터레이션 프로토콜을 준수하는 이터러블 즉, 이터러블은 데이터 공급자 역할
Array, String, Map, Set, TypedArray(Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array), DOM data structure(NodeList, HTMLCollection), Arguments

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

  • 데이터 소비자 : for...of문,Spread문법
  • 데이터 공급자(= 데이터소스) : 이터레이션 프로토콜을 준수한 이터러블
  • 다양한 데이터 소스가 각자의 순회방식을 갖는다면 데이터 소비자는 다양한 순회 방식을 지원해야한다.이는 효율적이지 않으므로
  • 즉, 다양한 데이터 소스가 하나의 순회 방식을 갖도록 규정하여 데이터 소비자가 효율적으로 데이터 소스를 사용할 수 있도록
  • 데이터 소비자와 데이터 소스를 연결하는 인터페이스 역할을 하는 것.

    1 ) 이터러블을 지원하는 데이터 소비자 내부에서 Symbol.iterator() 호출 후 이터레이터 생성
    2 ) 이터레이터의 next() 호출 후 이터러블 순회
    3 ) next() 반환한 이터레이터 리절트(result)객체의 value,done 프로퍼티 값 취득

for ...of 문

  • 내부적으로 이터레이터의 next() 를 호출하여 이터러블을 순회하며 next()가 반환한 이터레이터 리절트 객체의 value 프로퍼티 값을 for...of문의 변수에 할당
  • 이터레이터 리절트 객체의 done 프로퍼티값이 false이면 이터러블의 순회를 계속하고 true이면 순회 중단
// 배열
for (const item of ['a', 'b', 'c']) {
  console.log(item);
}

// 문자열
for (const letter of 'abc') {
  console.log(letter);
}

// Map
for (const [key, value] of new Map([['a', '1'], ['b', '2'], ['c', '3']])) {
  console.log(`key : ${key} value : ${value}`); // key : a value : 1 ...
}

// Set
for (const val of new Set([1, 2, 3])) {
  console.log(val);
}

이터러블 퀴즈 🧚‍♀️

01.

// [Symbol.iterator](): Iterator{ next(): {value, done}};
// 0부터 10이하까지 숫자의 2배를 순회하는 이터레이터(반복자) 만들기!
const multiple = {
  [Symbol.iterator]() {
    const max = 10;
    let num = 0;
    //이터레이터 오브젝트 반환
    return {
      //넥스트함수
      next() {
        //value와 done 반환
        return { value: num++ * 2, done: num > max };
      },
    };
  },
};

for (const num of multiple) {
  console.log(num);
}

02.

// [Symbol.iterator](): Iterator{ next(): {value, done}};
// 0부터 10이하까지 숫자의 2배를 순회하는 이터레이터(반복자) 만들기!

//초기값,최대값,콜백함수
function makeIterable(initialValue, maxValue, callback) {
  return {
    [Symbol.iterator]() {
      let num = initialValue;
      return {
        next() {
          return { value: callback(num++), done: num > maxValue };
        },
      };
    },
  };
}

const multiple = makeIterable(0, 10, (n) => n * 2);
for (const num of multiple) {
  console.log(num);
}

const single = makeIterable(0, 10, (n) => n);
for (const num of single) {
  console.log(num);
}

reference

참고

profile
냠소현 개발일지

0개의 댓글