ES6에서 도입된 프로토콜
순회 가능한 데이터 컬렉션(자료구조)을 만들기 위해 ECMAScript 사양에 정의하여 미리 약속한 규칙
이터레이션 프로토콜(iteration protocol)
이터러블 프로토콜(iterable protocol)
이터레이터 프로토콜(iterator protocol)
const array = [1, 2, 3];
// 배열은 Array.prototype의 Symbol.itertor 메서드를 상속받음
console.log(Symbol.iterator in array); // true
// 이터러블인 배열은 for...of 문으로 순회 가능함
for (const item of array) {
console.log(item); // 1, 2, 3
}
// 이터러블인 배열은 스프레드 문법의 대상으로 사용 가능함
console.log([...array]); // [1, 2, 3]
// 이터러블인 배열은 배열 디스트럭처링 할당의 대상으로 사용 가능함
const [a, ...rest] = array;
console.log(a, rest); // 1, [2, 3]
const obj = { a: 1, b: 2 };
// 일반 객체는 이터러블 프로토콜을 준수한 이터러블이 아님
console.log(Symbol.iterator in obj); // false
// 이터러블이 아닌 일반 객체는 for...of 문으로 순회 불가능
for (const item of obj) {
console.log(item);
}
// 이터러블이 아닌 일반 객체는 배열 디스트럭처링 할당의 대상으로 사용 못함
const [a, b] = obj; // TypeError: obj is not iterable
const obj = { a: 1, b: 2 };
console.log({ ...obj }); // { a: 1, b: 2 }
빌트인 이터러블 | Symbol.iterator 메서드 |
---|---|
Array | Array.prototype[Symbol.iterator] |
String | String.prototype[Symbol.iterator] |
Map | Map.prototype[Symbol.iterator] |
Set | Set.prototype[Symbol.iterator] |
TypedArray | TypedArray.prototype[Symbol.iterator] |
arguments | arguments.prototype[Symbol.iterator] |
NodeList | NodeList.prototype[Symbol.iterator] |
HTMLCollection | HTMCollection.prototype[Symbol.iterator] |
for (const item of [1, 2, 3]) {
console.log(item); // 1, 2, 3
}
const iterable = [1, 2, 3];
const iterator = iterable[Symbor.iterator]();
for (;;) {
const res = iterator.next();
if (res.done) break;
const item = res.value;
console.log(item); // 1 2 3
}
Note:
- for...in 문
- 객체의 프로토타입 체인 상에 존재하는 모든 프로토타입의 프로퍼티 중 프로퍼티 어트리뷰트 [[Enumerable]]의 값이 true인 프로퍼티를 순회하며 열거함
- 이때 프로퍼티 키가 심벌인 프로퍼티는 열거하지 않음
const arrayLike = {
0: 1,
1: 2,
2: 3,
length: 3
};
for (let i = 0; i < arrayLike.length; i++) {
console.log(arrayLike[i]); // 1 2 3
}
// TypeError: arrayLike is not iterable
for (const item of arrayLike) {
console.log(item);
}
ES6 전과 후의 순회 가능한 데이터 컬렉션 정의
이터러블은 for...of 문, 스프레드 문법, 배열 디스트럭처링 할당과 같은 데이터 소비자에 의해 사용되므로 데이터 공급자의 역할을 함
const fibonacci = {
[Symbol.iterator]() {
let [pre, cur] = [0, 1];
const max = 10;
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
}
const arr = [...fibonacci];
console.log(arr); // [1, 2, 3, 5, 8]
const [first, second, ...rest] = fibonacci;
console.log(first, second, rest); // 1 2 [3, 5, 8]
// 이터러블이면서 이터레이터인 객체
{
[Symbol.iterator]() { return this; }
next() {
return { value: any, done: boolean };
}
}
const fibonacciFunc = function (max) {
let [pre, cur] = [0, 1];
return {
[Symbol.iterator]() { return this; }
next() {
[pre, cur] = [cur, pre + cur];
return { value: cur, done: cur >= max };
}
};
};
let iter = FibonacciFunc(10);
for (const num of iter) {
console.log(num); // 1 2 3 5 8
}
console.log(iter.next()); // { value: 1, done: false}
console.log(iter.next()); // { value: 2, done: false}
console.log(iter.next()); // { value: 3, done: false}
console.log(iter.next()); // { value: 5, done: false}
console.log(iter.next()); // { value: 8, done: false}
console.log(iter.next()); // { value: 13, done: true}
const fibonacciFunc = function (max) {
let [pre, cur] = [0, 1];
return {
[Symbol.iterator]() { return this; }
next() {
[pre, cur] = [cur, pre + cur];
return { value: cur };
}
};
};
for (const num of fibonacciFunc()) {
if (num > 10000) break;
console.log(num); // 1 2 3 5 8 ... 4181 6765
}
// 배열 디스트럭처링 할당을 통해 무한 이터러블에서 3개의 요소만 취득
const [f1, f2, f3] = fibonacciFunc();
console.log(f1, f2, f3); // 1 2 3
위 예제의 fibonacciFunc 함수는 무한 이터러블을 생성함
위 예제의 이터러블은 지연 평가를 통해 데이터를 생성함