반복자 만들기

프로그래머로서 우리가 가장 먼저 배우는 것 중 하나는 "the loop "입니다. 항상 반복해야 하는 배열이나 목록 또는 컬렉션, 탐색이 필요한 키와 값을 가진 객체나 맵 또는 사전이 있습니다. 반복은 핵심 프로그래밍 개념입니다.

배열과 맵은 사물의 모음이며 반복하기 전에 명시적으로 정의해야 합니다. 빈 배열이나 선언으로 시작할 수 있으며 여기에 항목을 푸시할 수 있습니다. 예시:

const things = ['headphone', 'keyboard', 'mouse']
const friends = {
    tomo: 'nuxt expert',
    jt: 'writes nasty sqls',
    deco: 'the leader',
    van: 'php guru'
} 

things.push('cables')

// one of the ways of iterating arrays
for (const thing of things) {
  console.log(thing)
}

// iterate the key of objects
for (const name in friends) {
  console.log(`${name} - ${friends[name]}`)
}



배열이나 객체를 반복하는 방법에는 여러 가지가 있습니다. 몇 가지 예를 들자면:
  • for(const i = 0; i < arr.length; i+=1)
  • for...of MDN
  • for...in MDN
  • while() MDN
  • Array.forEach MDN
  • Array.map MDN
  • Array.filter MDN
  • Array.reduce MDN

  • 배열이나 객체(Map, Set 등)에 대한 한 가지는 무엇을 얻고 있는지 알고 있다는 것입니다. 배열에 항목을 푸시할 수 있지만 무엇을 푸시했는지 알고 있습니다. 역동적이지 않습니다. 배열에 있는 항목이 있으면 제거할 때까지 그대로 유지됩니다. 또한 메모리에서 해당 공간을 차지합니다.

    반복자 프로토콜


    value 반복에서 얻는 것next을 계산하는 동적 배열이 있다면 어떨까요? 당신이 만든 공식을 기반으로 작동한다면 어떨까요? 반복자 패턴을 사용해야 합니다. 구현이 매우 간단하다는 것을 알 수 있습니다. JS 프로그래머들 사이에서 잘 알려져 있고 다른 언어에서도 따르는 프로토콜입니다. 반복자는 next() 메서드가 있는 객체입니다. 객체에서 next() 함수를 호출하면 두 가지 속성이 있는 객체인 반복자 결과를 얻을 수 있습니다. 즉, 반복자의 상태를 유지하는 부울 값인 done와 반환하려는 항목을 유지하는 value입니다. 간단한 범위 반복자를 만들어 봅시다. 이 범위 반복자는 시작, 끝 및 단계를 제공하여 숫자 범위를 만들 수 있게 해줍니다.

    // iterator protocol: an agreed interface
    function numberRangeIterator(start, end, step) {
      let index = start
      return {
        next() {
          if (index > end) {
            return { done: true, value: 'thanks for using me' } // value is optional here but you can use it to return meta info
          }
          const value = index
          index += step
          return { done: false, value }
        }
      }
    }
    
    const iterator = numberRangeIterator(3, 30, 3)
    let iteratorResult = iterator.next()
    while (!iteratorResult.done) {
      console.log(iteratorResult.value)
      iteratorResult = iterator.next()
    }
    


    알겠어? 매우 간단하면서도 강력합니다. 두 가지 참고 사항:
  • next 함수는 더 이상 요소가 없음을 나타내기 위해 done: true를 반환하고 반대해야 합니다. 그러나 필수는 아니며 영원히 실행되는 반복자를 가질 수 있습니다!
  • 당신은 done: false를 갖거나 {value}만 반환할 수 있으며 위의 코드는 잘 작동할 것입니다.

  • function randomNumberIterator() {
      return {
        next() {
          return { done: false, value: Math.random() }
        }
      }
    }
    
    const rIterator = randomNumberIterator()
    let rIteratorResult = rIterator.next()
    while (!rIteratorResult.done) {
      console.log(rIteratorResult.value)
      rIteratorResult = rIterator.next()
    }
    


    위의 이터레이터를 언제 사용할지 생각할 수 없지만 난수를 무한히 생성할 수 있는 이터레이터를 보여주고 싶었습니다.

    반복 가능한 프로토콜



    Iterable 프로토콜은 모든 객체가 반복자를 반환하도록 JS 언어 내에서 표준을 정의함으로써 한 단계 더 나아갑니다. iterable[Symbol.iterator]라는 반복자 메서드를 구현하는 객체입니다. 위에서 언급한 이터레이터에 이터러블을 사용할 때 가장 좋은 점은 for...of 와 같은 배열을 반복하는 데 JS 네이티브 API를 사용할 수 있다는 것입니다. numberRangeIterator를 iterable로 빌드해 봅시다.

    class NumberRange {
      constructor(start, end, step) {
        this.start = start
        this.end = end
        this.step = step
      }
      // for an object/class to classify as iterable
      // it has to implement [Symbol.iterator]
      [Symbol.iterator]() {
        let index = this.start
        return {
          next: () => {
            if (index > this.end) {
              return { done: true }
            }
            const value = index
            index += this.step
            return { value }
          }
        }
      }
    }
    
    const myRange = new NumberRange(3, 30, 3)
    
    for (const num of myRange) {
      console.log(num)
    }
    


    Iterable 클래스를 정의하는 데 거의 동일한 양의 코드가 사용되었으며 대부분의 코드를 재사용했습니다. 그러나 아름다움은 반복자를 사용하는 방식에 있습니다. for...of를 사용하면 깔끔하고 간결해 보입니다. 나는 위의 while 루프보다 이것을 선호합니다. 하지만 여기서 멈추지 않습니다. 이 반복 가능 항목을 사용할 수 있는 다른 방법이 있습니다. 스프레드 연산자와 함께 사용할 수 있습니다.

    const myRange2 = new NumberRange(5, 20, 4)
    console.log(...myRange2) // prints 5 9 13 17
    


    또는 분해 및 할당

    const myRange2 = new NumberRange(5, 20, 4)
    
    const [first, second, third] = myRange2
    console.log(first, second, third) // prints 5 9 13
    

    Array.from(iterable) , Set([iterable]) , Promise.all(iterable) 및 심지어 stream.Readable.from(iterable) 와 같은 반복 가능 항목을 전달할 수 있는 반복 가능 항목을 허용하는 다른 JS 내장 API가 있습니다.

    Read more about iterators here . 일반 배열처럼 취급할 수 있지만 본질적으로 동적이며 필요할 때만 값을 계산합니다. 그러나 비동기 반복자의 영역에 들어가기 시작하면 상황이 약간 복잡해집니다. 그러나 그것은 또 다른 날입니다.

    좋은 웹페이지 즐겨찾기