JavaScript 中 Iterable,Iterator,Generator 三者的区别与联系

在 JavaScript 中,咱们常常会看到可迭代对象,迭代器和生成器的概念,它们之间有什么区别和联系呢,我就是想经过这篇文章总结一下,把这个问题搞明白。javascript

Interable(可迭代对象)

Iterable 是指有 [Symbol.iterator] 属性的对象,这个属性 obj[Symbol.iterator] 就是 Iterator(迭代器)。也能够说可迭代对象是实现了 Symbol.iterator 方法的对象。java

可迭代对象能够被 for..of 循环遍历,咱们最常进行迭代操做的可迭代对象就是 Array,其实还有其余可迭代对象,例如 String、Set、Map、函数的 arguments 对象和 NodeList 对象等,这些对象都有默认的 Symbol.iterator 属性。git

Iterator(迭代器)

Iterator 必须有 next() 方法,它每次返回一个 {done: Boolean, value: any} 对象,这里 done:true 代表迭代结束,不然 value 就是下一个要迭代的值。github

手写实现一个 Iterator

假设咱们 range 对象,咱们但愿对其使用 for..of 循环:segmentfault

let range = {
  from: 1,
  to: 5
};

// 咱们但愿能够这样:
// for(let num of range) ... num=1,2,3,4,5 
复制代码

为了让 range 对象可迭代,咱们须要为对象添加一个名为 Symbol.iterator 的方法。当 for..of 循环启动时,它会调用这个方法(若是没找到,就会报错)。这个方法必须返回一个 迭代器(iterator) —— 一个有 next 方法的对象。今后开始,for..of 仅适用于这个被返回的对象。当 for..of 循环但愿取得下一个数值,它就调用这个对象的 next() 方法。next() 方法返回的结果的格式必须是 {done: Boolean, value: any},当 done=true 时,表示迭代结束,不然 value 是下一个值。异步

let range = {
  from: 1,
  to: 5
};

// for..of 循环首先会调用这个
range[Symbol.iterator] = function() {

  // 它返回迭代器对象,接下来 for..of 仅与此迭代器一块儿工做
  return {
    current: this.from,
    last: this.to,

    // next() 在 for..of 的每一轮循环迭代中被调用
    next() {
      // 它将会返回 {done:.., value :...} 格式的对象
      if (this.current <= this.last) {
        return { done: false, value: this.current++ };
      } else {
        return { done: true };
      }
    }
  };
};

// 如今它能够运行了!
for (let num of range) {
  alert(num); // 1, 而后是 2, 3, 4, 5
}
复制代码

请注意可迭代对象的核心功能:关注点分离。range 自身没有 next() 方法。相反,是经过调用 range[Symbol.iterator]() 建立了另外一个对象,即所谓的“迭代器”对象,而且它的 next 会为迭代生成值。所以,迭代器对象和与其进行迭代的对象是分开的。函数

从技术上说,咱们能够将它们合并,并使用 range 自身做为迭代器来简化代码。ui

就像这样:this

let range = {
  from: 1,
  to: 5,

  [Symbol.iterator]() {
    this.current = this.from;
    return this;
  },

  next() {
    if (this.current <= this.to) {
      return { done: false, value: this.current++ };
    } else {
      return { done: true };
    }
  }
};

for (let num of range) {
  alert(num); // 1, 而后是 2, 3, 4, 5
}
复制代码

如今 range[Symbol.iterator]() 返回的是 range 对象自身:它包括了必需的 next() 方法,并经过 this.current 记忆了当前的迭代进程。这样更短,对吗?是的。有时这样也能够。spa

但缺点是,如今不可能同时在对象上运行两个 for..of 循环了:它们将共享迭代状态,由于只有一个迭代器,即对象自己。可是两个并行的 for..of 是很罕见的,即便在异步状况下。

无穷迭 Interator

此外,咱们还能够将 range 设置为 range.to = Infinity,这时 range 则成为了无穷迭代器。或者咱们能够建立一个可迭代对象,它生成一个无穷伪随机数序列。也是可能的。next 没有什么限制,它能够返回愈来愈多的值,这是正常的。固然,迭代这种对象的 for..of 循环将不会中止。可是咱们能够经过使用 break 来中止它。

Generator

Generator 是一个特殊函数,调用返回一个 Generator。

未完待续……

参考:

相关文章
相关标签/搜索