사용자 정의 이터러블, 이터러블/이터레이터 프로토콜 정의

윤성민·2020년 7월 22일
0

이터러블 구현해보기

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들이 이터러블 프로토콜을 따른다고 볼 수 있다.

profile
기록은 기억보다 강하다.

0개의 댓글