一文带你搞懂JavaScript的Generator函数

开发 前端
本文基于JavaScript基础,介绍了Generator函数 ,重点介绍了如何进行Generator 组合,采用图文结合的方式。采用JavaScript语言,能够更直观的的理解,希望能够帮助读者更好的学习。

[[422297]]

大家好,我是进阶学习者。

一、概念

常规函数只会返回一个单一值(或者不返回任何值)。

而 Generator 可以按需一个接一个地返回(“yield”)多个值。它们可与 iterable 完美配合使用,从而可以轻松地创建数据流。

二、Generator 函数

要创建一个 generator,需要一个特殊的语法结构:function*,即所谓的 “generator function”。

Generator 函数与常规函数的行为不同。在此类函数被调用时,它不会运行其代码。而是返回一个被称为 “generator object” 的特殊对象,来管理执行流程。

例如,可以创建一个 generator 并获取其第一个产出的(yielded)值:

  1. function* generateSequence() { 
  2.   yield 1; 
  3.   yield 2; 
  4.   return 3; 
  5. let generator = generateSequence(); 
  6. let one = generator.next(); 
  7. alert(JSON.stringify(one)); // {value: 1, done: false

截至目前,只获得了第一个值,现在函数执行处在第二行:

图片

让再次调用 generator.next()。代码恢复执行并返回下一个 yield 的值:

  1. let two = generator.next(); 
  2.  
  3. alert(JSON.stringify(two)); // {value: 2, done: false

如果第三次调用 generator.next(),代码将会执行到 return 语句,此时就完成这个函数的执行:

  1. let three = generator.next(); 
  2. alert(JSON.stringify(three)); // {value: 3, done: true

运行结果:

三、Generator 是可迭代的

当你看到 next() 方法,或许你已经猜到了 generator 是 可迭代(iterable)的。(译注:next() 是 iterator 的必要方法)

可以使用 for..of 循环遍历它所有的值:

  1. function* generateSequence() { 
  2.   yield 1; 
  3.   yield 2; 
  4.   return 3; 
  5. let generator = generateSequence(); 
  6. for(let value of generator) { 
  7.   alert(value); // 1,然后是 2 

运行结果:

for..of 写法是不是看起来比 .next().value 优雅多了?

注:

上面这个例子会先显示 1,然后是 2,然后就没了。它不会显示 3!

这是因为当 done: true 时,for..of 循环会忽略最后一个 value。因此,如果想要通过 for..of 循环显示所有的结果,必须使用 yield 返回它们:

  1. function* generateSequence() { 
  2.   yield 1; 
  3.   yield 2; 
  4.   yield 3; 
  5. let generator = generateSequence(); 
  6. for(let value of generator) { 
  7.   alert(value); // 1,然后是 2,然后是 3 

因为 generator 是可迭代的,可以使用 iterator 的所有相关功能。

例如:spread 语法 ...:

  1. function* generateSequence() { 
  2.   yield 1; 
  3.   yield 2; 
  4.   yield 3; 
  5. let sequence = [0, ...generateSequence()]; 
  6. alert(sequence); // 0, 1, 2, 3 

运行结果:

四、Generator 组合

Generator 组合(composition)是 generator 的一个特殊功能,它允许透明地(transparently)将 generator 彼此“嵌入(embed)”到一起。

例如,有一个生成数字序列的函数:组合的 generator 的例子:

  1. function* generateSequence(start, end) { 
  2.   for (let i = start; i <= end; i++) yield i; 
  3. function* generatePasswordCodes() { 
  4.   // 0..9 
  5.   yield* generateSequence(48, 57); 
  6.   // A..Z 
  7.   yield* generateSequence(65, 90); 
  8.   // a..z 
  9.   yield* generateSequence(97, 122); 
  10. let str = ''
  11. for(let code of generatePasswordCodes()) { 
  12.   str += String.fromCharCode(code); 
  13. alert(str); // 0..9A..Za..z 

运行结果:

generator.throw

上面的例子中观察到的那样,外部代码可能会将一个值传递到 generator,作为 yield 的结果。

但是它也可以在那里发起(抛出)一个 error。这很自然。

因为 error 本身也是一种结果,要向 yield 传递一个 error,应该调用 generator.throw(err)。

在这种情况下,err 将被抛到对应的 yield 所在的那一行。

例:

"2 + 2?" 的 yield 导致了一个 error:

  1. function* gen() { 
  2.   try { 
  3.     let result = yield "2 + 2 = ?"; // (1) 
  4.     alert("The execution does not reach here, because the exception is thrown above"); 
  5.   } catch(e) { 
  6.     alert(e); // 显示这个 error 
  7.   } 
  8. let generator = gen(); 
  9.  
  10. let question = generator.next().value; 
  11.  
  12. generator.throw(new Error("The answer is not found in my database")); // (2) 

运行结果:

五、总结

本文基于JavaScript基础,介绍了Generator函数 ,重点介绍了如何进行Generator 组合,采用图文结合的方式。采用JavaScript语言,能够更直观的的理解,希望能够帮助读者更好的学习。

欢迎大家积极尝试,有时候看到别人实现起来很简单,但是到自己动手实现的时候,总会有各种各样的问题,切勿眼高手低,勤动手,才可以理解的更加深刻。

代码很简单,希望对你学习有帮助。

 

责任编辑:姜华 来源: 前端进阶学习交流
相关推荐

2021-09-28 07:12:10

avaScriptCurrying柯里化

2023-03-06 21:29:41

mmap技术操作系统

2019-08-06 09:00:00

JavaScript函数式编程前端

2022-08-15 15:39:23

JavaScript面向对象数据

2021-12-01 11:40:14

Python 输入输出

2021-09-11 10:41:27

PythonPickle模块

2021-12-29 17:38:17

JavaScripttypeof前端

2021-10-14 10:25:05

JavaScript类型函数

2021-10-11 10:19:48

Javascript 高阶函数前端

2021-08-05 06:54:05

观察者订阅设计

2021-11-06 10:18:30

Python变量常量

2024-04-12 12:19:08

语言模型AI

2023-05-31 13:32:08

Javalambda函数

2022-03-24 08:51:48

Redis互联网NoSQL

2020-05-11 14:35:11

微服务架构代码

2021-07-21 09:24:25

MongoDB数据库 Python

2021-03-22 10:05:59

netstat命令Linux

2023-09-08 08:20:46

ThreadLoca多线程工具

2023-09-15 12:00:01

API应用程序接口

2023-04-12 08:38:44

函数参数Context
点赞
收藏

51CTO技术栈公众号