简单学习遍历器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
}
相关文章
相关标签/搜索