簡單學習遍歷器Iterator

遍歷器iterator

ES6以後數據結構除了數組和對象,又添加了Map和Set。遍歷器是一種接口規格,任何數據結構只要部署這個接口,就能夠完成遍歷操做javascript

提供了一個指針,經過指針的指向進行遍歷操做java

它提供了一個指針,默認指向當前數據結構的起始位置。也就是說,遍歷器返回一個內部指針,
第一次調用next方法,將指針指向第一個成員,第二次調用next方法,指針指向第二個成員數組

下面是一個模擬遍歷器指針的例子數據結構

function makeIterator(array) {
  let nextIndex = 0
  return {
      next: function() {
          return (nextIndex < array.length) ? {value: array[nextIndex++], done: false} : {value: undefined, done: true}
      }
  }
}

let it = makeIterator(['a', 'b'])
it.next() // {value: 'a', done: false}
it.next() // {value: 'b', done: false}
it.next() // {value: 'undefined', done: false}

遍歷器是一個對象,具備next方法,調用next方法,就能夠遍歷事先給定的數據結構this

Iterator接口的目的,就是爲全部的數據結構提供一種統一的訪問機制,就是for of循環prototype

默認的Iterator接口部署在數據結構的Symbol.iterator屬性,或者說數據結構具備該屬性就能夠認爲是可遍歷的指針

有三類數據結構原生具有了Iterator接口:數組、類數組對象、Set和Map,能夠直接使用for of方法
而對象須要在Symbol.iterator的屬性上部署遍歷器方法,才能夠for ofcode

下面是經過遍歷器實現指針結構的例子對象

// 在原型鏈上部署System.iterator方法,調用該方法,會返回遍歷器對象iteator。調用該對象的next方法,在返回一個值的同時,自動將內部指針指向下一個實例
function test (value) {
    this.value = value
    this.next = null
}

test.prototype[Symbol.iterator] = function () {
    let iterator = {
        next: next // iterator.next是一個function
    }

    let current = this
    
    function next () {
        if (current) {
            let value = current.value
            let done = current == null
            current = current.next
            return {
                value: value,
                done: done
            }
        } else {
            return {
                done: true
            }
        }
    }   
    return iterator
}

let one = new test(1),
    two = new test(2),
    three = new test(3);

one.next = two
two.next = three

for (let i of one) {
    console.log(i) // 1 2 3
}

還有一種簡單操做,對於類數組對象接口

NodeList.prototypoe[Symbol.iterator] = Array.prototype[Symbol.iterator]

默認調用iterator接口的場合

  • 解構賦值
  • 擴展運算符
  • yield*
  • Arrat.from()
  • Map和Set

部署Symbol.iterator最簡單實現是結合Generator

let myIterable = []
myiIterable[Symbol.iterator] = function* () {
    yield 1
    yield 2
    yield 3
}
[...myIterable] // [1, 2, 3]

// 或者
let obj = {
    * [Symbol.iterator]() {
        yield 'hello'
        yield 'world'
    }
}
for (let x of obj) {
    console.log(x) // hello world
}
  • 而對於對象來講,是不能直接使用for of的,須要使用yield包裝如下
// 如下狀況報錯
let e = {
    a: 1,
    b: 'bbb'
}

for (let [key, value] of e) {
    console.log() // error,e is not iterable
}

// 使用yield包裝一下
function* (obj) {
    for (let key of Object.keys(obj)) {
        yield [key, obj[key]]
    }
}

for (let [key, value] of entries(obj)) {
    console.log(key, '->', value) 
}
// a -> 1
// b -> 2
// c -> 3

JavaScript 原有的 for...in 循環,只能得到對象的鍵名,不能直接獲取鍵值。ES6 提供 for...of 循環,容許遍歷得到鍵值。

var arr = ["a", "b", "c", "d"];

for (a in arr) {
  console.log(a); // 0 1 2 3
}

for (a of arr) {
  console.log(a); // a b c d
}
相關文章
相關標籤/搜索