이전 포스팅인 확산 연산자와 구조 분해 할당에서 'Iterable
객체' 라는 말을 자주 사용했는데, 이번 포스팅에서 이터레이터를 통해 Iterable
이 무엇인지 자세히 알아보려고 한다!😁
Iterable
객체는 이터레이터(Iterator)를 이용해 객체의 요소들을 차례차례 가져올 수 있는 객체를 말한다.
배열이 가장 대표적인 Iterable
객체이므로, 배열을 예로 들어서 설명하겠다!
const arr = ['H', 'e', 'l', 'l', 'o'];
const it = arr.values(); // get iterator
for(let i = 0; i <= arr.length; i++){
console.log(it.next());
/*
* { value: 'H', done: false }
* { value: 'e', done: false }
* { value: 'l', done: false }
* { value: 'l', done: false }
* { value: 'o', done: false }
* { value: undefined, done: true }
*/
}
결과를 보면 배열을 순회하면서 요소를 출력하는데, 기존의 index
를 이용해 배열의 요소를 순회하는것이 아니라 arr.values()
메서드를 이용해 iterator
를 얻어오고, next()
메서드로 배열을 순회하는것을 볼 수 있다!😲
위에서 설명한 배열 말고도 Map
, Set
, String
처럼 다양한 Iterable
객체가 존재한다.
그런데 이미 정의되어있는 Iterable
객체 말고도 사용자가 임의로 어떤 객체를 Iterable
객체로 만들 수 있는 방법이 존재하는데, 그걸 가능하게 하는것이 바로 Iteration protocol
이다!😆
자세한 내용은 아래에서 설명하도록 하고, 일단은 코드를 보고나서 이해하도록 하자!
const customIterable = {
// Iteration protocol
[Symbol.iterator] : function() {
const arr = [1, 2, 3, 4, 5];
let index = 0;
return {
next() {
if(index < arr.length)
return { value : arr[index++], done : false };
return { value : undefined, done : true};
}
}
}
}
const it = customIterable[Symbol.iterator]();
let now = it.next();
while(!now.done) {
console.log(now); /*
* { value: 1, done: false }
* { value: 2, done: false }
* { value: 3, done: false }
* { value: 4, done: false }
* { value: 5, done: false }
*/
now = it.next();
}
console.log(it.next()); // { value: undefined, done: true }
평범한 객체인데도 Iterable
객체처럼 동작이 가능한 것을 볼 수 있다. 이는 해당 객체가 Iteration protocol
을 준수했기 때문이다.
Iteration protocol
은 Iterable protocol
과 Iterator protocol
이 있다. 자세한 내용은 아래 설명을 참고하도록 하자!😊
Iterable protocol
은 어떤 객체가 [Symbol.iterator]()
메서드를 가지고 있고, 해당 메서드를 호출 시 Iterator
를 반환하면 Iterable protocol
을 준수했다고 할 수 있다.
Iterator protocol
은 객체에 next()
메서드가 구현되어 있고, 해당 메서드가 { value : var, done : boolean }
형태의 객체를 반환하는 객체를 말한다. 이 객체를 Iterator
라고 부른다.
이렇게 Iteration protocol
을 준수한 객체는 Iterable
객체라고 부를 수 있고, for ... of
반복문이나 전에 설명했던 확산 연산자 의 사용이 가능해진다!😮
위에서 봤던 Iterator
는 객체를 순회하다가 done : true
로 마지막 요소라는 것을 알려주었다.
하지만 항상 done : false
로 만들어서 Iterator
가 끝나지 않게 할수도 있다.
아래의 예제를 보도록 하자!
const twice = {
[Symbol.iterator]() {
let i = 1;
return {
next() {
return { value : i *= 2, done : false};
}
}
}
}
for(let num of twice) {
if(num > 1024)
break;
console.log(num);
/*
* 2
* 4
* 8
* 16
* 32
* 64
* 128
* 256
* 512
* 1024
*/
}
위 코드에서 if(num > 1024)
로 break
를 걸지 않았다면, num
값이 Infinity
가 나오더라도 계속해서 이전 값에 2를 곱해주는 연산을 계속해서 하게 된다.
참고 자료
[Iteration & for ... of | PoiemaWeb]
https://poiemaweb.com/es6-iteration-for-of