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 |
댓글