const iterable = {
[Symbol.iterator]() {
let i = 3
return {
next() {
return i == 0 ? { done: true } : { value: i--, done: false }
},
[Symbol.iterator]() {
return this
},
}
},
}
let iter = iterable[Symbol.iterator]();
for (const a of iter) log(a); // 3 2 1
log(iter.next()); // {value:3, done: false}
log(iter.next()); // {value:2, done: false}
log(iter.next()); // {value:1, done: false}
log(iter.next()); // {done: true}
이터러블은 next()
를 통해 다음 값에 접근할 수 있고, [Symbol.iterator]()
를 통해 자기 자신을 반환할 수 있어야 한다.
const arr2 = [1, 2, 3];
for (const a of arr2) log(a); // 1 2 3
let iter2 = arr2[Symbol.iterator]();
iter2.next();
for (const b of iter2) log(b); // 2 3
log(iter2[Symbol.iterator]); // f [Symbol.iterator](){ [native code] }
log(iter2[Symbol.iterator]() == iter2); // true
// 이터레이터가 자기 자신을 반환하는 Symbol.iterator 메소드를 가지고 있을 때 잘 만들어진 이터러블이라 할 수 있다.
자바스크립트 뿐만 아니라, 오픈소스, 브라우저에 사용하는 Web API에서 구현된 값들(예를 들어 DOM과 관련된 값들)도 이터레이터 프로토콜을 따르고 있다.
log(document.querySelectorAll('*'))
// [html, head, script, body, script, script, script, script, script]
for (const a of document.querySelectorAll('*')) log(a);
// <html>
// <head>..</head>...
const all = document.querySelectorAll('*');
log(all[Symbol.iterator]()); // Array Iterator {}
let iter3 = all[Symbol.iterator]();
log(iter.next()); // {value: html, done: false}
log(iter.next()); // {value: head, done: false}
log(iter.next()); // {value: script, done: false}
for of 구문을 수행하는 것으로 보아 element들이 이터러블 프로토콜을 따른다고 볼 수 있다.