codermun 2021. 8. 10. 09:25
728x90

사용자 정의 Iterable을 구현하면서

Iterable을 더 자세히 알아보자.

 


3, 2, 1 순서로 출력되는 Iterable을 만들어보자.

Iterable은 Symbol.iterator Method를 구현하고 있어야 하며

Iterable이 가지고 있는 Symbol.iterator Methoditerator 를 반환해야한다.

반환하는 iterator는  next Method를 가지고 있으며

next는 {value, done}을 가지고 있는 객체를 반환해야 한다


아래와 같은 Iterable은 Symbol.iterator Method를 통해서 iterator를 반환 할 수 있고 next를 통해서

내부의 값을 조회할 수 있게 된다.

<script>
        console.log('------------------');
        const iterable = {
            [Symbol.iterator]() {
                let i = 3;
                return {
                    next() {
                        return i === 0 ? {value:undefined, done:true} : {value : i--, done: false};
                    }
                }
            }
        }

        let iterator = iterable[Symbol.iterator]();
        console.log(iterator.next());
        console.log(iterator.next());
        console.log(iterator.next());
        console.log(iterator.next());
        console.log(iterator.next());
    </script>

 

내부의 값을 조회할 수 있다는 이야기는 아래와 같이 순회를 할 수 있다는 의미이다.

for (const a of iterable) console.log(a);


즉,

Iterable에 Symbol.iterator가 구현되어 있고

Symbol.iterator의 실행 결과로 Iterator를 반환되고

또 그 결과는 내부적으로 next를 실행하면서 const a 에 {value} 값을 하나씩 담게 되면서 순회할 수 있게 된다.

 

하지만!!

현재까지는 Iterable&iterator protocol에 모든 속성을 구현하지는 않은 상태이다!

 

Array와 같이 잘 구현된 Iterable 예시를 보자

const arr = [1, 2, 3];
        let iter2 = arr[Symbol.iterator]();
        iter2.next()
        for (const a of iter2) console.log(a);

Array와 같이 잘 구현된 Iterable 은 iterator를 만들었을때

해당 iterator를 진행하다가 순회할 수 있고 

next를 실행하지 않고 iterator 자체로 순회 할 수 있다.

 

앞선 리스트 순회 포스팅에서 알아보았듯

반환된 iterator 역시 Symbol.iterator를 가지고 있으며

iterator에서 실행한 Symbol.iterator 값은 자기자신이다.

 

즉, iterator가 자기자신을 반환하는 Symbol.iterator Method를 가지고 있을때

well formed iterator라 부르며이때 iterable은 

well formed iterable이라 부른다.

const arr = [1, 2, 3];
        let iter2 = arr[Symbol.iterator]();
        console.log(iter2);
        console.log(iter2[Symbol.iterator]);
        console.log(iter2[Symbol.iterator]() === iter2);
        for (const a of iter2) console.log(a);


사용자 Iterable을 모든 속성을 구현할 수 있도록 속성을 추가해보자.

이전까지 진행되어 있던 자기상태에서 계속해서 next를 할 수 있도록 만들어 둔것이 well formed iterator이다.

const iterable = {
            [Symbol.iterator]() {
                let i = 3;
                return {
                    next() {
                        return i === 0 ? {value:undefined, done:true} : {value : i--, done: false};
                    },
                    [Symbol.iterator](){return this;}
                }
            }
        }

        let iterator = iterable[Symbol.iterator]();

        for (const a of iterable) console.log(a);

 

따라서, 이처럼 well formed iterator 로 만들어야 모든 속성을 구현했다고 할 수 있으며

만약 iterator가 well formed iterator가 아니라면

iterator 가 iterable이 아니라고 에러가 발생하게 된다.

const iterable = {
            [Symbol.iterator]() {
                let i = 3;
                return {
                    next() {
                        return i === 0 ? {value:undefined, done:true} : {value : i--, done: false};
                    },
                     // [Symbol.iterator](){return this;}
                }
               
            }
        }

        let iterator = iterable[Symbol.iterator]();

        for (const a of iterator) console.log(a);

 

즉, iterator 도 iterable이 되도록 만들면 (Iterator 가 well formed Iterator 라면)

iterator로 반환한 값을 for...of에 넣어도 순회가 가능하다.

iterable 을 넣어도 순회가 되고

iterable 을 iterator로 만든 상태에서 넣어도 순회가 되고

일정부분 next를 진행한 후에도 순회가 될 수 있다.

for (const a of iterator) console.log(a);
for (const a of iterable) console.log(a);

 

Iterable&iterator protocol은 ES6에서 지원하는 내장 값만을 지원하는 것이 아니다.

오픈소스 라이브러리 , 브라우저 Wep API(DOM 등등) 자바스크립트에서 순회가 가능한 값은

이 Iterable&iterator protocol 규약을 따르기 시작했다.

 

DOM API 예제

DOM 또한 Iterable&iterator protocol 규약을 따른다.

즉, Symbol.iterator와 next 메소드등 위의 well formed iterator 속성을 모두 가지고 있다!!

for (const a of document.querySelectorAll('*')) console.log(a);

 

const all = document.querySelectorAll('*');
        console.log(all);

all 이라는 값이 Symbol.iterator 가 구현되어 있기 때문이다.

const all = document.querySelectorAll('*');
        let it3 = all[Symbol.iterator]();
        console.log(all[Symbol.iterator]);
        console.log(it3);
        console.log(it3.next());
        console.log(it3.next());
        console.log(it3.next());

 


SUMMARY

well formed iterator

Iterator이면서 Iterable인 객체를 well-formed iterator이라고 한다.

 

Array, Set, Map, NodeList 같은 것들은 well-formed iterator라고 할 수 있으며이는 반횐된 Iterator 의 Symbol.iterator 는 자기자신이라는 특징을 가진다.

iter[Symbol.iterable]() === iter ==> true

 

ES6 이후 출현한 for...of , for..in 등의 반복문의 경우

내부적으로 Symbol.iterator, welll-formed iterable, next 등 Iterable&iterator protocol 규약을 따르며

Iterable&iterator protocol 규약을 따르는 문법, 연산자, 객체 등등의 것들과 함께 사용하고 동작할 수 있는 것이다.

728x90