温故而知新:ES6迭代器和生成器

68 阅读3分钟

迭代器

定义

对于早期的JavaScript表示集合的数据结构,主要是数组对象,后来ES6中又增加了Map和Set集合。

迭代器(iterator)它是一种接口,为各种不同的数据结构提供统一的访问机制,任何数据结构只要部署了Iterator接口,就可以很方便的完成遍历操作(依次处理该数据结构的所有成员)

作用

  • 为JavaScript中各种数据结构,提供统一便捷的访问接口
  • 使得数据结构中的成员能按照某个顺序排序
  • ES6中提供了一种新的遍历命令for...of循环,Iterator接口主要供for...of消费

迭代遍历过程

  1. 创建一个指针对象,指向当前数据结构的起始位置,也就是说,遍历器对象本质上,就是一个指针对象
  2. 第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员
  3. 第二次调用指针对象的next方法,指针就指向数据结构中的第二个成员
  4. 不断的调用指针对象的next方法,直到它指向数据结构的结束位置
const makeIterator = (arr) => {
  let index = 0
  return {
    next() {
      return index < arr.length ? {
        value: arr[index++],
        done: false
      } : {
        value: undefined,
        done: true
      }
    }
  }
}
var it = makeIterator(['1', '2'])
console.log(it.next()) // { value: '1', done: false}
console.log(it.next()) // { value: '2', done: false}
console.log(it.next()) // { value: undefined, done: true}

指针对象的next方法,用来移动指针,开始时,指针指向数组的起始位置,然后每次调用next方法,指针就会指向数组下一个成员,第一次调用,指向1,第二次调用指向2。

next方法返回一个对象,表示当前数据的成员信息,这个对象有value和done两个属性,value属性返回当前位置的成员,done属性是一个boolean值,表示遍历是否结束,即是否还有必要进行下一次的next方法的调用,如果value值返回undefined,done返回true则表示遍历完成

具备Ietrator接口的数据

  • Array
  • String
  • Map
  • Set
  • 函数的arguments参数
  • nodeList对象(dom集合对象)

生成器

概念

  • generator函数是ES6提供的一种异步编程解决方案,语法与传统的函数完全不一样
  • 从语法上,可以理解成generator函数是一个状态机,封装了多个内部状态
  • generator函数除了状态机,还是一个遍历器对象生成函数
  • generator函数内部,yield可暂停,next方法可启动,每次返回的是yield后的表达式结果

写法

  • function函数关键字与函数名直接有个*号
  • 函数体内部使用yield表达式,定义不同的内部状态
function* myGenerator() {
  console.log('准备执行中...')
  yield 'hollo world';
  yield 'i am a developer';
}
let MG = myGenerator() // 返回指针对象
const a = MG.next() //  {value: "hello", done: false}
const b = MG.next() // { value: 'i am a developer', done: false}
const c = MG.next() // { value: undefined, done: true}

与iterator的关系

JavaScript中对象没有部署Symbol.iterator属性,因此使用for...of遍历时会报错

let obj = { userrName: 'tony', age: 20 }
for (let i of obj) {
  console.log(i) //  Uncaught TypeError: obj is not iterable
}

由于genrator函数就是一个迭代器生成函数,因此可以把Generator赋值给对象的Symbol.iterator属性,使得该对象具有iterator接口

let obj = { userrName: 'tony', age: 20 }
obj[Symbol.iterator] = function* myTest() {
  yield 1;
  yield 2;
  yield 3;
};
for (let i of obj) {
  console.log(i) // 1 2 3
}