EC6 이전의 순회 가능한 데이터 컬렉션(array, string, array-like, DOM collection 등)은 통일된 규약(protocol)없이 각자 나름의 구조를 가지고 for문, for…in문, forEach 메서드 등 다양한 방법으로 순회할 수 있었다.
// Array(1024).keys()는 iterator이기 때문에
// map과 같은 배열 메서드를 사용할 수 없다.
// Array.from을 통해 iterator 객체를 배열로 만들 수 있다.
// 그러면 배열 메서드를 사용할 수 있게 된다.
const users = Array.from(Array(1024).keys()).map(
(id): User => ({
id,
name: `denis${id}`,
})
);
34.5 이터레이션 프로토콜의 필요성
이터레이션 프로토콜을 준수하는 이터러블
Array, String, Map, Set, TypedArray(Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array), DOM data structure(NodeList, HTMLCollection), Arguments
다양한 **데이터 공급자(Data provider)**가 각자의 순회 방식을 갖는다면 **데이터 소비자(Data consumer)**는 다양한 데이터 소스의 순회 방식을 모두 지원해야 한다.
이는 효율적이지 않다. 하지만 다양한 데이터 공급자가 이터레이션 프로토콜을 준수하도록 규정하면 데이터 소비자는 이터레이션 프로토콜만을 지원하도록 구현하면 된다.
이터레이션 프로토콜은 데이터 소비자와 데이터 공급자를 연결하는 인터페이스의 역할을 한다.
34.6 사용자 정의 이터러블
34.6.1 사용자 정의 이터러블 구현
주석을 하나씩 보면서 이터러블 객체를 어떻게 구현하는지 확인할 수 있다.
이터러블 객체는 for … of 문, 스프레드 문법, 디스트럭처링 할당에서 사용할 수 있다.
let range = {
from: 1,
to: 10,
};
// Symbol.iterator 메서드를 구현하여 이터러블 프로토콜을 준수한다.
range[Symbol.iterator] = function () {
let [current, last] = [this.from, this.to];
// Symbol.iterator 메서드는 next 메서드를 소유한 이터레이터를 반환한다.
// next 메서드는 이터레이터 리절트 객체를 반환한다.
return {
next() {
if (current <= last) {
return { done: false, value: current++ };
} else {
return { done: true };
}
},
};
};
// for ... of 문에서 이터러블을 순회할 수 있다.
// 이터러블인 range 객체를 순회할 때마다 next 메서드가 호출된다.
for (let num of range) {
console.log(num);
}
// 스프레드 문법 가능
const arr = [...range];
console.log(arr);
// 디스트럭처링 할당 가능
const [first, second, ...rest] = range;
console.log(first, second, rest);
34.6.2 이터러블을 생성하는 함수
위 예제를 보면 range 객체의 from과 to 프로퍼티 값이 1과 10으로 각각 고정되어 있다.
range의 from과 to 값을 외부에서 전달받아 반환하는 함수를 만들면 된다.
const range = function (from, to) {
let [current, last] = [from, to];
// 이터러블을 반환한다.
return {
[Symbol.iterator]() {
return {
next() {
if (current <= last) {
return { done: false, value: current++ };
} else {
return { done: true };
}
},
};
},
};
};
for (let num of range(3, 10)) {
console.log(num);
}