• 이터레이터 & 제네레이터 ( iterator & generator )

    2021. 8. 9.

    by. KimBangg

    1. ES5의 리스트 순회

    • 일반적인 프로그래밍 언어와 같이 숫자라는 "키"로 순회 하였습니다.
    const list = [1,2,3];
    
    for ( var i = 0; i < list.length; i++ ) {
        console.log(list[i]);
    }

       

       

      

    2. ES6의 리스트 순회

    • ES6 에서는 가독성을 위해 for of의 사용을 권고합니다.
    • 하지만 일반적인 경우와는 달리 "키"가 없는데, 어떤 방식으로 순회를 하는걸까요?
    // 훨씬 간결하고, 선언적인 순회 방법
    const ( const val of list ) {
        console.log(val);
    }

       

       

      

    3.  [ Array, Set, Map  ] 을 통해 알아보는 이터러블 & 이터레이터

     

    • 3-1 이터러블 & 이터레이터 이란?
      - 자바스크립트의 [ 배열, 객체, 맵 ] 은 이터러블, 이터레이블 프로토콜을 따르는 방식으로 구현이 되어있습니다.
      • - 이터러블 ( iterable ) -
        • 이터레이터를 관리하는 [Symbol.iterator()] 를 가진 값. 
      • - 이터레이터 ( iterator )
        • - { value, done } 객체를 리턴하는 next()를 가진 값.
      • - 이터레블 / 이터레이터 프로토콜
        • 이터러블을 for .. of, 전개 연산자 등과 함께 동작 하도록 하는 규약
    • 3-2 자바스크립트 배열, 맵, 셋의 작동 방식
      • 아래의 예시를 보면 arr는 key로 접근이 가능하지만, set과 Map은 key로 접근이 불가능합니다.
      • 즉, 이 사실을 통해 for.. of는 키를 바탕으로 값에 접근 하지 않는다는 것을 알 수 있습니다.
      •  // Array [ 키로 접근해서 순회가 가능 => console.log(a[0]) ]
          
          const arr  = [1,2,3];
          
          for ( const val of arr ) {
          console.log(val);  
          }
          
          // set [ 반면에 Set & Map 은 키로 접근이 안된다. ]
          
          const set = new Set([1,2,3]);
          
          console.log(set[1]); // undefined
        
          for ( const ele of set ) {
          console.log(ele);
          }
          
          // Map
          
          const map = new Map([['a',1], ['b',2], ['c', 3]]);
          
          console.log(map[1]); // undefined
        
          for ( const obj of map ) {
          console.log(obj);
          }
    • 작동 방식
      • 그렇다면 어떻게 동작하는걸까요?
      • arr, map, set은 모두 이터레이블 프로토콜을 기반으로 작동합니다.
        • const arr  = [1,2,3];
          arr[Symbol.iterator] = null;
          
          // output: TypeError: arr is not iterable
          for ( const val of arr ) {
            console.log(val);  
           }
      • 이터러블 프로토콜은 next를 포함하는 iterator 메소드로 구성이 되어있습니다.
      • 그리하여, 값이 있는 경우 done : false & value 가 전달이 되고 없는 경우는 done : true 값이 전달됩니다.
        • let iterator = arr[Symbol.iterator]();
          iterator.next() // { value : 1, done : false }
          iterator.next() // { value : 2, done : false }
          iterator.next() // { value : 3, done : false }
          iterator.next() // { value : undefined, done : true }
        • const arr1 = [1,2,3];
          let iter1 = arr[Symbol.iterator]();
          iterator.next() // { value : 1, done : false }
          iterator.next() // { value : 1, done : false }
          
          for ( const a of iter1 ) {
            console.log(a); // 3
          }  

       

      

    4. 사용자 정의 이터러블

    • 이터러블에 대한 보다 자세한 이해를 위해 하단의 코드를 작성 해보았습니다.
    • 이터레이블 내부에는 총 길이, next(), iterator 를 포함 하고 있습니다.
    const iterable = {
        [Symbol.iterator]() {
    
            let i = 3 // parameter.legnth
    
            return {
                //  next는 인덱스와 done 여부를 반환하는 함수입니다.
                next() {
                    return i === 0 ? {done : true}  : { value  : i-- , done : false }
                },
    
                // well-formed iterable 은 iterataor를  통해서 모두 구동이 가능 해야 합니다.
                [Symbol.iterator]() {
                    return this;
                }
            }
        }
    }
    
    let iterator = iterable[Symbol.iterator]();
    
    // iterator & iterator 모두 구동 가능
    for ( const a of iterator ) {
        console.log(a);
    }
    

       

       

      

     

    5. 전개 연산자

    const a = [1,2];
    // a[Symbol.iterator] = null;
    console.log([...a, ...[3,4]]);
    console.log(a);

       

       

      

    6. 제너레이터

    • 제너레이터는 이터레이터이자 이터레이터를 생성하는 함수 입니다.
    • 제너레이터는 순회할 값을 문장으로 표현하는 것이라고도 말할 수 있습니다.
    function *gen() {
        yield 1;
        yield 2;
        yield 3;
    
        return 100;
    }
    
    let iter = gen();
    iter[Symbol.iterator]();
    console.log(iter.next()); // { value : 1, done : false }
    console.log(iter.next()); // { value : 2, done : false }
    console.log(iter.next()); // { value : 3, done : false }
    console.log(iter.next()); // { value : 100, done : ture }
    
    for ( const a of gen() ) console.log(a)

       

       

      

    7.  제너레이터 & 이터레이터 ( odds )

    • 제너레이터를 다음과 같이 응용하여 사용 할 수 있습니다.
    function *limit(l, iter) {
        for ( const a of iter ) {
             yield a;
             if ( a === l ) {
                return;
            }
    }
    
    function *infinity(i = 0) {
        while ( true ) {
            yield i++;
        }
    }
    
    function *odds(ele) {
    
        for ( const a of limit( ele, infinity(1)) ) {
             if ( a % 2 ) {
                yield i;
            }
    
           // if ( a === ele ) return;
        }
    
    }
    
    let iter2 = odds(10);
    console.log(iter2.next());
    console.log(iter2.next());
    
    
    // 평가 할 때만, 생성이 되기 때문에 브라우저가 멈추는 일은 없음.
    let iter3 = infinity();
    console.log(iter3.next());
    console.log(iter3.next());
    console.log(iter3.next()); 
    
    let iter4 = limit(4, [1,2,3,4,5,6]);
    // ...
    
    for ( const a of odds(40) ) console.log(a);
    

       

       

      

    8. 구조 분해, Spread

     

    console.log(...odds(10));
    console.log(...odds(10), ...odds(20));
    
    const [head, ...tail] = odds(5);
    console.log(head);
    console.log(tail);
    
    const [a, b, ...rest ] = odds(10);
    console.log(a);
    console.log(b);
    console.log(rest);

    'Develop > JavaScript' 카테고리의 다른 글

    [ JavaScript ] 변수란?  (0) 2021.08.17
    [ JavaScript ] 정규식 ( Regular Expression)  (0) 2021.08.03
    [ JavaScript ] 실행 컨텍스트 (Execution Context)  (0) 2021.07.19
    [ JavaScript ] let vs var  (0) 2021.07.14
    [ JavaScript ] This 란 ?  (0) 2021.07.14

    댓글