ES6学习之迭代器(Iterator)和生成器(generator)

122 阅读3分钟

迭代器(Iterator)

它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作。

Iterator 的作用有三个:

  • 一是为各种数据结构,提供一个统一的、简便的访问接口;
  • 二是使得数据结构的成员能够按某种次序排列;
  • 三是 ES6 创造了一种新的遍历命令for...of循环,Iterator 接口主要供for...of消费。

它具有一些专门为迭代过程设计的专有接口。所有具有迭代器的对象都有一个next方法。每次调用next方法返回一个对象,表示当前数据成员的信息。这个对象具有valuedone两个属性,value属性返回当前位置的成员,done属性是一个布尔值,表示遍历是否结束,即是否还有必要再一次调用next方法。

{value:返回的值, done:boolean}。

ES5模拟迭代器

function createIterator(items) {
    var i = 0;
    return {
        next: function() {
            var done = (i >= items.length);
            var value = !done ? items[i++] : undefined;
            return {
                done: done,
                value: value
            };
        }
    };
}
var iterator = createIterator([1, 2, 3]);
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next()); // "{ value: 2, done: false }"
console.log(iterator.next()); // "{ value: 3, done: false }"
console.log(iterator.next()); // "{ value: undefined, done: true }"
// 之后的所有调用
console.log(iterator.next()); // "{ value: undefined, done: true }"

对于具有迭代器接口的数据结构

  • Array
  • Map
  • Set
  • String
  • TypedArray
  • 函数的 arguments 对象
  • NodeList 对象

对他们调用Symbol.iterator 就能得到遍历器对象了,可以用next()方法了

let arr = ['a', 'b', 'c'];
let iter = arr[Symbol.iterator]();

iter.next() // { value: 'a', done: false }
iter.next() // { value: 'b', done: false }
iter.next() // { value: 'c', done: false }
iter.next() // { value: undefined, done: true }

生成器(Generator)

生成器是一种返回一个迭代器对象的函数

Generator函数是ES6提供的一种异步编程解决方案,形式上也是一个普通函数,但有几个显著的特征:

  •  function关键字与函数名之间有一个星号 "*" (推荐紧挨着function关键字)
  •   函数体内使用 yield 表达式,定义不同的内部状态 (可以有多个yield)
  •   直接调用 Generator函数并不会执行,也不会返回运行结果,而是返回一个遍历器对象(Iterator Object)
  •   依次调用遍历器对象的next方法,遍历 Generator函数内部的每一个状态
{
  // 传统函数
  function foo() {
    return 'hello world'
  }

  foo()   // 'hello world',一旦调用立即执行


  // Generator函数
  function* generator() {
    yield 'status one'         // yield 表达式是暂停执行的标记,只能使用在生成器中  
    return 'hello world'
  }

  let iterator = generator()   // 调用 Generator函数,函数并没有执行,返回的是一个Iterator对象
  iterator.next()              // {value: "status one", done: false},value 表示返回值,done 表示遍历还没有结束
  iterator.next()              // {value: "hello world", done: true},value 表示返回值,done 表示遍历结束
}

传统函数调用后立即执行并输出了返回值;Generator函数则没有执行而是返回一个Iterator对象,并通过调用Iterator对象的next方法来遍历,函数体内的执行看起来更像是“被人踢一脚才动一下”的感觉

yield只能在generator中使用