ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [JS] Iterable/Iterator 프로토콜
    백수의 개발/웹 2021. 8. 19. 00:42

    Iterator Protocol

    Array, Map, Set와 같은 컬렉션 내 각 항목 처리는 매우 흔한 연산이다.

    iterator protocol을 통해 이러한 컬렉션을 더 잘 사용할 수 있다.

    iterator는 두 개의 속성( value, done)을 반환하는 next() 메소드 사용하여 객체의 iterator protocol을 구현한다.

     

    실제 구현되어있는 iterator를 실행해보자.

    const arr = ['a', 'b', 'c', 'd', 'e'];
    const iter = arr[Symbol.iterator]();
    console.log(iter.next()) // { value: "a", done: false }
    console.log(iter.next()) // { value: "b", done: false }
    console.log(iter.next()) // { value: "c", done: false }
    console.log(iter.next()) // { value: "d", done: false }
    console.log(iter.next()) // { value: "e", done: false }
    console.log(iter.next()) // { value: undefined, done: true }

    이와 같이 iterator에서 next를 호출하여 위와 같이 실행할 수 있다.

     

    이러한 iterator가 내부적으로 어떻게 구현될 수 있는지 알아보자.

     

    Array의 iterator 구현해보기

    Symbol.customIterator = Symbol.for('customIterator');
    Array.prototype[Symbol.customIterator] = function() {
        const self = this;
        let i = 0;
        return {
            next: function() {
                if (i === self.length) return { value: undefined, done: true };
    
                const value = self[i];
                i++;
                return { value: value, done: false };
            },
            [Symbol.customIterator]: self[Symbol.customIterator]
        }
    }

    위와 같이 직접 구현해보면 기존 iterator와 동일한 결과를 얻을 수 있다.

    const arr = ['a', 'b', 'c', 'd', 'e'];
    const customIter = arr[Symbol.customIterator]();
    console.log(customIter.next()) // { value: "a", done: false }
    console.log(customIter.next()) // { value: "b", done: false }
    console.log(customIter.next()) // { value: "c", done: false }
    console.log(customIter.next()) // { value: "d", done: false }
    console.log(customIter.next()) // { value: "e", done: false }
    console.log(customIter.next()) // { value: undefined, done: true }

     

    iterable 규약

    이러한 iterable이 구현된 것들은 for...of, 전개 연산자 등과 함께 동작하도록 규약되어있다.

    const arr = [1, 2, 3, 4];
    
    for(const value of arr) {
    	console.log(value);
    }
    
    const [first, second, ...rest] = arr;
    const arrarr = [...arr, ...arr];
    
    console.log(first); // 1
    console.log(second); // 2
    console.log(rest); // [3, 4]
    console.log(arrarr); // [1, 2, 3, 4, 1, 2, 3, 4]

    generator

    generator와 yield를 통해 이러한 iterator를 만들 수 있다.

    function *gen() {
    	yield 'a';
    	yield 'b';
    	yield 'c';    
    }
    
    const iter = gen();
    
    console.log(iter.next()); // { value: "a", done: false }
    console.log(iter.next()); // { value: "b", done: false }
    console.log(iter.next()); // { value: "c", done: false }
    console.log(iter.next()); // { value: undefined, done: true }

    function *을 통해 iterator의 next메서드들이 생성이 되고, yield를 통해 (value, doen)이 생성이 된다고 보면된다.

     

    generator에 대한 내용은 추후 더 자세하게 다루어보도록 하겠다.

    댓글

Designed by Tistory.