본문 바로가기
프로그래밍 개발/JS ES6+

Javascript ES6+ Iterator

by Jinseok Kim 2020. 12. 18.
반응형

 

 

Iterator

 

 

반복을 위해 설계된 특별한 인터페이스를 가진 객체라고 할 수 있다.


- 객체 내부에는 `next()` 메소드가 있는데,

- 이 메소드는 `value`와 `done` 프로퍼티를 지닌 객체를 반환한다.
`done` 프로퍼티는 boolean값이다.

 

 

 

Iterator 구현 예시 코드

 

객체 내의 프로퍼티를 iterable한 개체로 활성화 시켜주는 것을 확인 할 수 있다.

const iter = {
    items : [10, 20, 30],
    count: 0,
    next () {
    const done = this.count >= this.items.length
    return{
        done,
 value: !done ?this.items[this.count++]:undefined
    }
  }
}
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())

//결과:
//{done: false, value: 10}
//{done: false, value: 20}
//{done: false, value: 30}
//{done: true, value: undefined}
//{done: true, value: undefined}

 

 

 

 

 

 

 

 

 

객체 내의 iterator 구현 과정

 

 

 

 

1) 객체에는 'next' 메소드가 존재해야 한다.

 

const iter = {
  next () {}
}

 

 

 

 

2) next 메소드는 다시 객체를 반환해야 한다.

 

const iter = {
  next () {
    return {}
  }
}

 

 

 

 

 

3) 반환되는 객체에는 boolean 값을 가지는 done 프로퍼티가 존재해야 한다.

 

const iter = {
  next () {
	return {
      done: false
    }
  }
}
console.log(iter.next())

 

 

 

 

 

4) value 프로퍼티를 추가하고, 일정시점에 done을 true로 변환할 수 있게끔 한다.

 

const iter = {
  val: 0,
  next () {
    const isDone = ++this.val >= 5
    return {
      done: isDone,
      value: !isDone ? this.val : undefined
    }
  }
}
console.log(iter.next()) //  {done: false, value: 1}

 

 

 

 

 

 

iterable한 개체 만들기

 

 

※ `for...of`, `...(spread)` 등은 모두 개체 내부 (또는 개체의 `__proto__`)의 [Symbol.iterator]를 실행한 결과를 바탕으로, `done`이 `true`가 될 때까지 계속하여 `next()`를 호출하는 식으로 구현되어 있다.

 

 

 

 

 

1) 개체의 Symbol.iterator 메소드를 호출하면 iterator가 반환되도록 한다.

 

const createIterator = () => {
  return {
    next () {
      return {
        done: false
      }
    }
  }
}
const obj = {
  [Symbol.iterator]: createIterator
}
console.log(...obj)

 

 

 

 

 

2) done이 true가 나오지 않는 한 이터레이트시 무한정 반복실행한다. 따라서 적절한 시점에 done을 true로 바꾸어주어야 한다.

 

const createIterator = () => {
  let count = 0
  return {
    next () {
      return {
        done: count > 3
      }
    }
  }
}
const obj = {
  [Symbol.iterator]: createIterator
}
console.log(...obj)

 

 

 

 

3) value 프로퍼티를 추가하면 완성된다.

 

const createIterator = function () {
  let count = 0
  const items = Object.entries(this)
  return {
    next () {
      return {
        done: count >= items.length,
        value: items[count++]
      }
    }
  }
}
const obj = {
  a: 1,
  b: 2,
  c: 3,
  d: 4,
  [Symbol.iterator]: createIterator
}
console.log(...obj) // ["a", 1] ["b", 2] ["c", 3] ["d", 4]

객체 내부에 직접 할당한 형태

const obj = {
  a: 1,
  b: 2,
  c: 3,
  d: 4,
  [Symbol.iterator] () {
    let count = 0
    const items = Object.entries(this)
    return {
      next () {
        return {
          done: count >= items.length,
          value: items[count++]
        }
      }
    }
  }
}
console.log(...obj)

또는 generator를 실행한 결과 역시 iterable하다.

const obj = {
  a: 1,
  b: 2,
  c: 3,
  d: 4,
  *[Symbol.iterator] () {
    yield* Object.entries(this)
  }
}
console.log(...obj)

 

 

 

 

정리

 

 

 

  • `for-of`, `(spread operator)`, `forEach 메소드` 등은 내부적으로
  • -`[Symboliterator]`를 실행한 결과 객체를 들고, 
  •  객체 내부의 `next()` 메소드를 
  •  `done 프로퍼티`가 `true`가 나올 때까지 반복하여 호출한다.
  •  즉, Symboliterator 메소드의 내용을 위 요구사항에 맞추어 구현하기만 하면 iterable한 객체이다.

 

 

 

 

 

반응형

'프로그래밍 개발 > JS ES6+' 카테고리의 다른 글

Javascript ES6+ Class  (0) 2020.12.21
Javascript ES6+ Generator  (0) 2020.12.18
Javascript ES6+ Iterable  (0) 2020.12.18
Javascript ES6+ Map  (0) 2020.12.16
Javascript ES6+ Set  (0) 2020.12.16

댓글