Iterator&Generator - ChoDragon9/posts GitHub Wiki

Iterator

๋‚ด๋ถ€ ํ‘œํ˜„๋ถ€๋ฅผ ๋…ธ์ถœํ•˜์ง€ ์•Š๊ณ  ์–ด๋–ค ๊ฐ์ฒด ์ง‘ํ•ฉ์— ์†ํ•œ ์›์†Œ๋“ค์„ ์ˆœ์ฐจ์ ์œผ๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•˜๋Š” ํŒจํ„ด์ด๋‹ค.

Iterable Protocol

์ˆœ์ฐจ์ ์œผ๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” Iterator๋ฅผ ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•œ ํ”„๋กœํ† ์ฝœ

Java์—์„œ Iterator๋ฅผ ๊ตฌํ˜„ํ•  ๋•Œ๋Š” hasNext/next ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜์ง€๋งŒ Javascript์—์„œ๋Š” next๋งŒ ์‚ฌ์šฉ๋œ๋‹ค.

์ฃต๋ฃŒ๋œ ๊ฒƒ์€ done property๊ฐ€ true์ผ ๋•Œ๋กœ ํ™•์ธ ๊ฐ€๋Šฅํ•˜๋‹ค.

const str = "hi"
const iterator = str[Symbol.iterator]()

console.log(iterator.next()) //{ value: 'h', done: false }
console.log(iterator.next()) //{ value: 'i', done: false }
console.log(iterator.next()) //{ value: undefined, done: true }

Iterator Protocol

๋ฐ์ดํ„ฐ๋ฅผ ์ˆœ์ฐจ์ ์œผ๋กœ ์ ‘๊ทผํ•  ๋•Œ ์‹คํ–‰๋˜๋Š” ํ”„๋กœํ† ์ฝœ

function makeIterator(array){
  var nextIndex = 0;

  return {
    next: function(){ //next ๋ฉ”์†Œ๋“œ๋ฅผ ๊ฐ€์ ธ์•ผ ํ•จ
      return nextIndex < array.length ?
        {value: array[nextIndex++], done: false} :
        {done: true};
         //done : iterator์˜ ๋ฐ˜๋ณต ์ž‘์—… ์ข…๋ฃŒ ์œ ๋ฌด. boolean ์‚ฌ์šฉ
         //value : iterator๋กœ ๋ถ€ํ„ฐ ๋ฐ˜ํ™˜๋˜๋Š” ๊ฐ’, done์ด true์ผ ๋•Œ ์ƒ๋žต ๊ฐ€๋Šฅ
      }
  };
}

var it = makeIterator(['yo', 'ya']);

console.log(it.next().value); // 'yo'
console.log(it.next().value); // 'ya'
console.log(it.next().done); // true

Customize Iterables

Object๋Š” Iterable ํ•˜์ง€ ์•Š์ง€๋งŒ Iterator/Iterable Protocol๋ฅผ ํ†ตํ•ด Iterable ํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

const obj = {
  name: 'Smith',
  age: 20,
  weight: 60
}

console.log([...obj]) //TypeError

obj[Symbol.iterator] = () => {
  const arr = Object.keys(obj)
  return {
    next () {
      return arr.length > 0 ?
        { value: obj[arr.pop()], done: false } :
        { done: true }
      }
    }
}

console.log([...obj]) // [60, 20, 'Smith']

Using Generator

const obj = {
  name: 'Smith',
  age: 20,
  weight: 60
}

obj[Symbol.iterator] = function* () {
  const arr = Object.keys(obj)
  yield obj[arr.pop()]
  yield obj[arr.pop()]
  yield obj[arr.pop()]
}

console.log([...obj]) // [60, 20, 'Smith']

Iterable data sources

Arrays, Maps, DOM queies, Strings, Sets, Arguments

Generator

yield๋กœ Iterator๋ฅผ ์‰ฝ๊ฒŒ ์ •์˜ํ•˜์—ฌ Iterable๋ฅผ ์‰ฝ๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Œ. ์ฝ”๋ฃจํ‹ด์„ ์ง€์›ํ•จ.

function*

ํ•จ์ˆ˜ ์‹คํ–‰ ์‹œ Generator Object๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. Generator Object์˜ ์ธํ„ฐํŽ˜์ด์Šค๋Š” next, return, throw๊ฐ€ ์žˆ๋‹ค.

next๋ฅผ ํ˜ธ์ถœํ•˜๊ฒŒ ๋˜๋ฉด yield์˜ ๊ฐ’์ด ๋ฐ˜ํ™˜๋˜๋ฉฐ, yield๋Š” Generator๋ฅผ ์ผ์‹œ์ •์ง€ ์‹œํ‚จ๋‹ค.

function* genFour () {
  yield 1
  yield 2
  yield 3
  return 4
}
let four = getFour()

Generators are both an iterator and an iterable.

four.next() // Object { value: 1, done: false)
four.next() // Object { value: 2, done: false)
four.next() // Object { value: 3, done: false)
four.next() // Object { value: 4, done: true)

[....getFour()] // Array [1, 2, 3, 4]

yield* yields every yield inside a called generator

function* flatten(arr){
  for (let x of arr) {
    if (x instanceof Array){
      yield* flatten(x)
    } else {
      yield x
    }
  }
}
let t = flatten([1, 2, [3, 4]])

cursor ์˜ˆ์‹œ

const log = txt => {
  console.log(`[cursor] ${txt}`)
}

function* getFour () {
  log(`getFour: 1`)
  yield 1
  log(`getFour: 2`)
  yield 2
  log(`getFour: 3`)
  yield 3
  log(`getFour: 4`)
  yield 4
}

for (const num of getFour()) {
  log(`num: ${num}`)
}

// "[cursor] getFour: 1"
// "[cursor] num: 1"
// "[cursor] getFour: 2"
// "[cursor] num: 2"
// "[cursor] getFour: 3"
// "[cursor] num: 3"
// "[cursor] getFour: 4"
// "[cursor] num: 4"