首页 > web前端 > js教程 > ES6发电机和迭代器:开发人员指南

ES6发电机和迭代器:开发人员指南

Christopher Nolan
发布: 2025-02-15 11:42:13
原创
879 人浏览过

ES6 Generators and Iterators: a Developer’s Guide

ES6为JavaScript语言引入了许多新特性。其中两个特性,生成器和迭代器,极大地改变了我们在更复杂的前端代码中编写特定函数的方式。

虽然它们可以很好地协同工作,但它们实际的功能可能有点令人困惑,所以让我们来仔细研究一下。

关键要点

  • ES6提供了一种更简洁的for循环编写方式,提供了一种更类似Python的方式来直接与数据集中的元素交互,使代码更易于阅读和编写。
  • ES6中的生成器是记住每次调用之间状态的函数。它们每次被调用时都可以生成序列中的下一个值,有效地创建自定义迭代。
  • 生成器函数中的“yield”关键字类似于“return”,但它保持函数的状态,允许它在下一次调用时从中断处继续执行。
  • 虽然Node和现代浏览器支持ES6特性,但旧版浏览器可能需要Babel等转译器将ES6代码转换为ECMAScript 5代码。

迭代器

迭代是编程中常见的做法,通常用于循环遍历一组值,转换每个值,或以某种方式使用或保存它以备后用。

在JavaScript中,我们一直都有这样的for循环:

for (var i = 0; i < foo.length; i++) {
  // 对i执行某些操作
}
登录后复制
登录后复制
登录后复制

但ES6给了我们另一种选择:

for (const i of foo) {
  // 对i执行某些操作
}
登录后复制
登录后复制

这可以说是更简洁、更容易使用,让我想起了Python和Ruby等语言。但是,关于这种新型迭代,还有一点非常重要需要注意:它允许您直接与数据集的元素交互。

假设我们想找出数组中的每个数字是否为素数。我们可以通过创建一个执行此操作的函数来做到这一点。它可能看起来像这样:

function isPrime(number) {
  if (number <= 1) {
    return false;
  } else if (number === 2) {
    return true;
  }

  for (var i = 2; i < number; i++) {
    if (number % i === 0) {
      return false;
      break;
    }
  }

  return true;
}
登录后复制
登录后复制

不是世界上最好的,但它有效。下一步是循环遍历我们的数字列表,并使用我们闪亮的新函数检查每个数字是否为素数。这很简单:

var possiblePrimes = [73, 6, 90, 19, 15];
var confirmedPrimes = [];

for (var i = 0; i < possiblePrimes.length; i++) {
  if (isPrime(possiblePrimes[i])) {
    confirmedPrimes.push(possiblePrimes[i]);
  }
}

// confirmedPrimes现在是[73, 19]
登录后复制
登录后复制

同样,它有效,但它很笨拙,这种笨拙很大程度上取决于JavaScript处理for循环的方式。但是,有了ES6,我们就在新的迭代器中得到了一个几乎类似Python的选项。因此,前面的for循环可以这样编写:

const possiblePrimes = [73, 6, 90, 19, 15];
const confirmedPrimes = [];

for (const i of possiblePrimes){
   if ( isPrime(i) ){
      confirmedPrimes.push(i);
   }
}

// confirmedPrimes现在是[73, 19]
登录后复制

这要干净得多,但最引人注目的是for循环。变量i现在代表名为possiblePrimes的数组中的实际项。因此,我们不再需要按索引调用它了。这意味着我们不必在循环中调用possiblePrimes[i],而只需调用i即可。

在幕后,这种迭代利用了ES6闪亮的新Symbol.iterator()方法。这个方法负责描述迭代,并且在被调用时,返回一个JavaScript对象,其中包含循环中的下一个值和一个done键,该键根据循环是否完成而为true或false。

如果您对这种细节感兴趣,您可以阅读Jake Archibald撰写的这篇精彩博文《Iterators gonna iterate》。当我们深入探讨本文的另一部分:生成器时,它也会让您很好地了解幕后发生了什么。

生成器

生成器(也称为“迭代器工厂”)是一种新型的JavaScript函数,用于创建特定的迭代。它们为您提供了特殊、自定义的循环遍历内容的方式。

好的,那么这一切意味着什么?让我们来看一个例子。假设我们想要一个函数,每次调用它时都会给我们下一个素数:

for (var i = 0; i < foo.length; i++) {
  // 对i执行某些操作
}
登录后复制
登录后复制
登录后复制

如果您习惯使用JavaScript,其中一些内容看起来有点像巫术,但实际上它并不太糟糕。我们在关键字function之后有那个奇怪的星号,但这只是告诉JavaScript我们正在定义一个生成器。

另一个奇怪的部分是yield关键字。这实际上是生成器在您调用它时吐出的内容。它大致相当于return,但它保留了函数的状态,而不是在每次调用它时都重新运行所有内容。它在运行时“记住”它的位置,因此下次您调用它时,它会从中断处继续执行。

这意味着我们可以这样做:

for (const i of foo) {
  // 对i执行某些操作
}
登录后复制
登录后复制

然后,每当我们想要获得——你猜对了——下一个素数时,都可以调用nextPrime:

function isPrime(number) {
  if (number <= 1) {
    return false;
  } else if (number === 2) {
    return true;
  }

  for (var i = 2; i < number; i++) {
    if (number % i === 0) {
      return false;
      break;
    }
  }

  return true;
}
登录后复制
登录后复制

您也可以只调用nextPrime.next(),这在您的生成器不是无限的情况下很有用,因为它返回一个这样的对象:

var possiblePrimes = [73, 6, 90, 19, 15];
var confirmedPrimes = [];

for (var i = 0; i < possiblePrimes.length; i++) {
  if (isPrime(possiblePrimes[i])) {
    confirmedPrimes.push(possiblePrimes[i]);
  }
}

// confirmedPrimes现在是[73, 19]
登录后复制
登录后复制

在这里,done键告诉您函数是否已完成其任务。在我们的例子中,我们的函数永远不会结束,理论上可以为我们提供所有直到无穷大的素数(如果我们有那么多的计算机内存的话)。

很酷,那么我现在可以使用生成器和迭代器了吗?

尽管ECMAScript 2015已经完成,并且已经存在多年了,但其特性(特别是生成器)的浏览器支持远未完善。如果您真的想使用这些和其他现代特性,您可以查看Babel和Traceur等转译器,它们会将您的ECMAScript 2015代码转换为等效的(如果可能)ECMAScript 5代码。

还有许多在线编辑器支持ECMAScript 2015,或者专门关注它,特别是Facebook的Regenerator和JS Bin。如果您只是想玩玩并了解JavaScript现在如何编写,那么这些值得一看。

结论

生成器和迭代器为我们处理JavaScript问题的方法提供了相当多的新灵活性。迭代器允许我们以更类似Python的方式编写for循环,这意味着我们的代码看起来更简洁,更容易阅读。

生成器函数使我们能够编写记住上次看到它们的位置的函数,并且可以从中断处继续执行。它们在实际记住的内容方面也可以是无限的,这在某些情况下非常方便。

对这些生成器和迭代器的支持很好。它们在Node和所有现代浏览器中都受支持,Internet Explorer除外。如果您需要支持旧版浏览器,最好的办法是使用Babel等转译器。

关于ECMAScript 2015生成器和迭代器的常见问题解答 (FAQ)

ECMAScript 2015中的迭代器和生成器有什么区别?

迭代器和生成器都是ECMAScript 2015的特性,用于处理数据流。迭代器是一个对象,允许程序员遍历集合中的所有元素。它有一个next()方法,返回序列中的下一个项目。另一方面,生成器是一个可以中途停止然后从停止处继续的函数。换句话说,生成器看起来像一个函数,但它的行为像一个迭代器。

如何在ECMAScript 2015中使用yield关键字?

yield关键字用于ECMAScript 2015暂停和恢复生成器函数(function*或旧版生成器函数)。yield可以从生成器函数返回一个值。这个返回值通常是一个具有两个属性的对象:value和done。value属性是计算yield表达式的结果,done是一个布尔值,指示生成器是否已生成其最后一个值。

ECMAScript 2015中next()方法的目的是什么?

next()方法是ECMAScript 2015中迭代器协议的关键部分。它返回一个具有两个属性的对象:value和done。value属性是迭代序列中的下一个值,done是一个布尔值,指示迭代是否完成。如果done为true,则迭代器已超出迭代序列的末尾。

如何在ECMAScript 2015中使用生成器进行异步编程?

ECMAScript 2015中的生成器可用于简化异步编程。它们可用于阻止执行以等待异步操作完成,而不会阻塞整个程序。这可以使异步代码看起来和行为更像同步代码,这更容易理解和推理。

ECMAScript 2015中for…of循环和for…in循环有什么区别?

ECMAScript 2015中的for…of循环用于循环遍历可迭代对象,例如数组、字符串、映射、集合等等。它使用语句调用自定义迭代钩子,这些语句将为每个不同属性的值执行。另一方面,for…in循环用于循环遍历对象的属性。它返回正在迭代的对象的键列表。

如何在ECMAScript 2015中创建自定义迭代器?

在ECMAScript 2015中,您可以通过定义一个具有next()方法的对象来创建自定义迭代器。此方法应返回一个具有两个属性的对象:value和done。value属性是迭代序列中的下一个值,done是一个布尔值,指示迭代是否完成。

Symbol.iterator在ECMAScript 2015中的作用是什么?

Symbol.iterator是ECMAScript 2015中一个特殊的内置符号。它用于指定对象的默认迭代器。当需要迭代一个对象时(例如在for…of循环的开头),它的@@iterator方法将不带任何参数被调用,并且返回的迭代器将用于获取要迭代的值。

你能提供ECMAScript 2015中生成器函数的示例吗?

当然,这是ECMAScript 2015中生成器函数的一个简单示例:

for (var i = 0; i < foo.length; i++) {
  // 对i执行某些操作
}
登录后复制
登录后复制
登录后复制

在这个例子中,idMaker函数是一个生成器,它产生一个数字序列。

如何在ECMAScript 2015中使用throw()方法和生成器?

ECMAScript 2015中的throw()方法可用于生成器,以恢复生成器函数的执行并从yield表达式抛出错误。throw()方法可用于处理生成器函数执行期间发生的错误。

done属性在ECMAScript 2015迭代器中的意义是什么?

done属性是一个布尔值,由ECMAScript 2015中的迭代器返回。它指示迭代器是否还有更多值要返回。如果done为true,则迭代器已超出迭代序列的末尾。如果done为false,则迭代器仍然可以生成更多值。

以上是ES6发电机和迭代器:开发人员指南的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板