1. 程式人生 > 其它 >ES6 Iterator迭代器 與 Generator生成器 如何用js封裝一個遍歷所有可迭代資料結構的方法

ES6 Iterator迭代器 與 Generator生成器 如何用js封裝一個遍歷所有可迭代資料結構的方法

ES6 Iterator迭代器 與 Generator生成器

1.1 為什麼要有 Iterator

在ES6語法中,有序資料結構已有許多
如Array、Set、Map、String、類陣列(如arguments)等
當我們不確定資料是何種型別但又要對它進行遍歷時,我們只能去做針對性的判斷處理
因此,一個統一的介面來遍歷所有資料型別是很有必要的,而Iterator扮演了這一角色

1.2 什麼是Iterator

  1. 具有[Symbol.iterator]屬性,且屬性值是function型別
  2. 執行此function返回一個迭代器物件,此物件有next方法可順序迭代子元素
  3. forof可遍歷此迭代器

在js中,實現了Iterator介面的資料結構都是可迭代的
具體表現為資料結構的[Symbol.iterator]屬性值是function型別

const isIterable = target => typeof target?.[Symbol.iterator] === 'function'

當迭代器順序執行完畢之後,後續執行返回的done為true,作為迭代結束的標誌

function arrLike(){
    const it = arguments[Symbol.iterator]()
    console.log(it) // Object [Array Iterator] {}
    console.log(it.next()) // { value: 1, done: false }
    console.log(it.next()) // { value: 2, done: false }
    console.log(it.next()) // { value: 3, done: false }
    console.log(it.next()) // { value: undefined, done: true }
}

arrLike(1,2,3)

封裝一個迭代函式,用於遍歷js中所有可迭代的資料結構

// 判斷是否可迭代
const isIterable = target => typeof target?.[Symbol.iterator] === 'function'

function each(target,callback){
    if(!isIterable(target)){
        throw 'the first parameter must be iterable(need a [Symbol.iterator] property)'
    }
    typeof callback !== 'function' && (callback = console.log)

    const iterator = target[Symbol.iterator]()

    // 或者用forof
    // for (const item of iterator) {
    //     callback(item)
    // }
    let item = {done:false}
    while(!item.done){
        item = iterator.next()
        !item.done && callback(item.value)
    }
}

each([2,3,4],console.log)
each('abc',console.log)

2 Generator生成器與迭代器

一個生成器函式必定返回一個生成器物件,並且這個物件符合迭代器協議
因此這個生成器物件可以被forof遍歷,同樣的具有next方法

function* testGen(){} 
console.log(testGen()) // Object [Generator] {}

function* helloWorldGenerator(){
    yield 'hello'
    yield 'world'
    yield 'generator'
    return 'end'
}

const genIterator = helloWorldGenerator()
console.log(genIterator.next()) // { value: 'hello', done: false }

each(genIterator,console.log)