ES2015에서 Iterable Protocol이 추가되었습니다.

Iterable Protocol에는 2가지 형태가 존재하는데, iterable과 iterator가 있습니다.

 

Iterable

iterable은 객체의 멤버를 반복할 수 있는 객체입니다.

iterable은 자바스크립트 객체의 요소들에 대해 반복되는 행동(예를 들어, for .. of 구문에서 어떤 값들이 루프를 돌고 있는가)을 정의할 수 있도록 해줍니다.

JavaScript에서 객체가 iterable하기 위해서는, object에는 [@@iterator] 메서드가 구현되어 있어야 합니다.

따라서 임의로 우리가 객체를 만들고 iterable하게 만들고 싶다면, object 프로퍼티에 Symbol.iterator를 추가해야 합니다.

 

객체는 반드시 하나의 Symbol.iterator 만을 가질 수 있습니다.

const iterable = new Object();

// obj[Symbol.iterator] 함수는 iterator 객체를 반환합니다.
iterable[Symbol.iterator] = function* () {
  yield 1;
  yield 2;
  yield 3;
};
// 전개 연산자를 이용해서 iterator의 값을 반복할 수 있습니다.
console.log([...iterable]); // 1 2 3
// for ... of 를 이용해서 iterator의 값을 반복할 수 있습니다.
for(var value of iterable) {
    console.log(value); // 1 2 3
}

객체가 iterated 될 때, @@iterator 메서드가 인자 없이 호출되고, @@iterator가 반환하는 iterator는 iterated되는 값들을 얻기 위해 사용됩니다.

@@iterator 메서드는 호출한 후 iterable한 객체를 반환하므로 generator 함수라고도 할 수 있습니다.  

Iterator

iterator 는 객체를 next 메서드로 순환할 수 있는 객체입니다.

iterator는 next() 메소드를 가지고 있고, next 메소드는 아래의 규칙에 따라 구현되어야 합니다.

  1. next 메소드는 arguments 가 없습니다.
  2. next 메소드는 done: boolean 과 value: any 를 포함하는 object 를 반환해야 합니다.
  3. next 메소드의 반복이 끝날때 done 은 true 를 반환해야 합니다.
const iterator = '132'[Symbol.iterator]();
iterator.next(); // {value: "1", done: false}
iterator.next(); // {value: "3", done: false}
iterator.next(); // {value: "2", done: false}
iterator.next(); // {value: undefined, done: true}

 

 

iterator 객체는 아래와 같이 만들 수 있습니다.

const obj = {};
// iterator를 생성하는 함수
// iterator는 이 함수의 반환값입니다.
const counter = count => (
  (i = 0) => ({
    next: () => (
      (i++ < count) ?
      { value: i, done: false } :
      { value: 0, done: true }
    )
  })
);
obj[Symbol.iterator] = counter(3);
console.log([...obj]); // [1, 2, 3]

 

 

Iterable 과 Iterator 의 구분

Object가 @@iterator 를 가지고 있다면, iterable 입니다.

Object에서 next 메서드가 값을 반복하면서, {done, value} 를 반환한다면, iterator 입니다.

 

Iteration protocols 의 예시

 

Javascript 에서 built-in object 중 iterable 를 가지고 있는 객체는 Array, TypedArray, String, Map, Set 가 있으며 이들의 메서드 중 일부는 iterator 객체를 반환합니다. 대표적으로 Object.entries( ), Object.keys( ), Object.values( ) 메서드 등이 있습니다. 

  • Object.entries( ) : 전달된 파라미터 객체가 가지는 (열거 가능한) 속성 [key, value] 쌍의 배열을 리턴합니다.
  • Object.keys( ) : 전달된 파라미터 객체가 가지는 (열거 가능한) 속성의 key 이름들로 이루어진 배열을 리턴합니다.
  • Object.values( ) : 전달된 파라미터 객체가 가지는 (열거 가능한) 속성의 값들로 이루어진 배열을 리턴합니다.

 

const arr = ['1', '2', '3'];

console.log([...arr.entries()]);
// [[0, '1'], [1, '2'], [2, '3']];
console.log([...arr.keys()]);
// [0, 1, 2];
console.log([...arr.values()]);
// ['1', '2', '3'];

const map = new Map([[1, '1'], [2, '2'], [3, '3']]);

console.log(map.entries());
// MapIterator {1 => "1", 2 => "2", 3 => "3"}
console.log(map.keys());
// MapIterator {1, 2, 3}
console.log(map.values());
// MapIterator {"1", "2", "3"}

const set = new Set([1, 2, 3]);

console.log(set.entries());
// SetIterator {1, 2, 3}
console.log(set.keys());
// SetIterator {1, 2, 3}
console.log(set.values());
// SetIterator {1, 2, 3}

문자열의 기본적인 iterator는 문자열의 요소들을 하나씩 반환합니다.

전개 연산자 또한 기본적으로 동일한 iteration protocol을 사용합니다.

let someString = 'hello';

let iterator = someString[Symbol.iterator]();
console.log(iterator + ''); // "[object String Iterator]"

console.log(iterator.next()); // {value: 'h', done: false }
console.log(iterator.next()); // {value: 'e', done: false }
console.log(iterator.next()); // {value: 'l', done: false }
console.log(iterator.next()); // {value: 'l', done: false }
console.log(iterator.next()); // {value: 'o', done: false }
console.log(iterator.next()); // {value: undefined, done: true }

console.log([...someString]); // ['h', 'e', 'l', 'l', 'o']

 

 

우리가 직접 @@iterator를 정의하여 iteration 특성을 재정의해봅시다.

// need to construct a String object explicitly to avoid auto-boxing
let someString = new String('hello');

someString[Symbol.iterator] = function () {
  return {
    // this is the iterator object, returning a single element (the string "bye")
    next: function () {
      return this._first ? {
        value: 'bye',
        done: (this._first = false)
      } : {
        done: true
      }
    },
    _first: true
  };
};

console.log([...someString]); // ["bye"]
console.log(someString + ''); // "hello"

 

 

 

출처 : MDN - Iteration protocols

복사했습니다!