说三道四技术文摘-感悟人生的经典句子
说三道四 > 文档快照

【探秘ES6】系列专栏:生成器

HTML文档下载 WORD文档下载 PDF文档下载
新一代JavaScript标准,ES6即将发布。【探秘ES6】系列专栏将一一剖析ES6的诸多新特性,让Web开发者对此有清晰全面的了解。本文为系列的第三篇,带你了解ES6的生成器。

ES6作为新一代JavaScript标准,即将与广大前端开发者见面。为了让大家对ES6的诸多新特性有更深入的了解,Mozilla Web开发者博客推出了《ES6 In Depth》系列文章。CSDN已获授权,将持续对该系列进行翻译,供大家学习借鉴。本文为该系列的第三篇。

ES6生成器介绍

什么是生成器呢?

请先看看以下代码。

function* quips(name) {  yield "hello " + name + "!";  yield "i hope you are enjoying the blog posts";  if (name.startsWith("X")) {    yield "it's cool how your name starts with X, " + name;  }  yield "see you later!";}

这是一段有关汤姆猫(talking cat)的代码。它看上去像是一个函数,是吗?在ES6中,它的名字是生成器函数,其与普通函数有很多相似的地方。但有两点不同:

  • 生成器函数以function*开头;
  • 在生成器函数中,yield是一个关键字,如同return。yield可以多次使用,作用是中断生成器,

    而在需要的时候可以恢复生成器的执行

所以生成器函数最大的特点是可以中断自己,但普通函数不可以。

生成器的作用

当使用quips()生成器函数时会出现什么情况呢?

> var iter = quips("jorendorff");  [object Generator]> iter.next()  { value: "hello jorendorff!", done: false }> iter.next()  { value: "i hope you are enjoying the blog posts", done: false }> iter.next()  { value: "see you later!", done: false }> iter.next()  { value: undefined, done: true }

对于普通quips(),它会马上执行直到出现返回或异常抛出等情况。在生成器函数中,调用方式是类似的:quips("jorendorff"),但是它不会马上执行。取而代之的是,它会返回一个已暂停的生成器对象(如上述代码的iter)。你可以把生成器对象看成是一个被暂停的函数调用。要特别说明的是生成器对象在生成器函数开始时被冻结,即第一行代码执行之前。

每当调用生成器对象的.next()方法时,函数恢复运行直至遇到下一个yield表达式,其作用是用于迭代。因此iter.next()的目的是为了返回不同的字符串。在最后的iter.next()中,使用done:true表示结束。到达函数末端意味着返回的结果是undefined,所以代码片段中使用value: undefined结尾。

从技术角度来看,每当生成器执行yield操作时,它的堆栈帧包括本地变量、参数、临时值等都会从堆中被移出。但是生成器对象会保留(拷贝)对该帧的引用,所以.next()可以重新激活它然后继续执行。这里特别要说明的是,生成器不是线程。当一个生成器执行时,它与其调用者都处于同一个线程,是按次序执行而不是并行运行。

可见生成器的作用是暂停本身的运行,然后恢复并继续执行,那么这究竟有何用处呢?

生成器就是迭代器

ES6迭代器不是内建的,可尝试通过使用[Symbol.iterator]()和.next()来进行创建。但是这种类似接口的做法不是最简便的方法。请看下面一个range迭代器例子,它的作用类似于C的for(;;)循环。

// This should "ding" three timesfor (var value of range(0, 3)) {  alert("Ding! at floor #" + value);}

具体的实现代码:

class RangeIterator {  constructor(start, stop) {    this.value = start;    this.stop = stop;  }  [Symbol.iterator]() { return this; }  next() {    var value = this.value;    if (value < this.stop) {      this.value++;      return {done: false, value: value};    } else {      return {done: true, value: undefined};    }  }}// Return a new iterator that counts up from 'start' to 'stop'.function range(start, stop) {  return new RangeIterator(start, stop);}

要查看运行情况请点击这里。

可见迭代器的生成并不是件简单的事情。那么如果采用生成器来实现,应该如何编写呢?

function* range(start, stop) {  for (var i = start; i < stop; i++)    yield i;}

要查看运行情况请点击这里。

对比是很明显的,上述代码仅需4行代码就完成了相同的功能,因为生成器就是迭代器。所有生成器都内建了对.next()和[Symbol.iterator]()的支持,你只需要负责循环的实现就可以了。

除此以外,作为迭代器使用的生成器还可以实现哪些功能呢?

  • 使任何对象可迭代。方法是编写一个生成器函数,然后对每个值进行迭代。然后使用对象的[Symbol.iterator]方法与生成器函数进行绑定。
  • 简化数组功能。如果要实现以数组形式返回函数结果,可以这样写:

// Divide the one-dimensional array 'icons'// into arrays of length 'rowLength'.function splitIntoRows(icons, rowLength) {  var rows = [];  for (var i = 0; i < icons.length; i += rowLength) {    rows.push(icons.slice(i, i + rowLength));  }  return rows;}

如果使用生成器编写,可以把代码简化为:

function* splitIntoRows(icons, rowLength) {  for (var i = 0; i < icons.length; i += rowLength) {    yield icons.slice(i, i + rowLength);  }}

后者与前者的区别是不是一次就计算所有结果并返回一个数组,而是先返回一个迭代器,然后按次序按需进行计算。

  • 返回特殊长度数组。数组是有长度限制的,但是透过生成器迭代特性,可以产生无限的序列。
  • 重构复合循环。当编写一个复杂的循环时,可以提出产生数据的部分,把它改写为一个独立的生成器函数。例如(var data of myNewGenerator(args))。
  • 进行迭代运算的配套工具。ES6并没有提供有关筛选、映射、迭代数据集操作的扩展库。但是借助生成器,我们可以围绕它来简单地创建相关工具。

例如,要在DOM节点上实现与Array.prototype.filter类似的功能,可以这样编写:

function* filter(test, iterable) {  for (var item of iterable) {    if (test(item))      yield item;  }}

可见,生成器真的妙不可言。借助生成器可以方便地实现定制的迭代操作,而迭代是ES6中贯穿始终的新的数据和循环标准。

生成器和异步代码

请看一段代码:

}).on('close', function () {  done(undefined, undefined);}).on('error', function (error) {  done(error);});

异步APIs提供的是错误处理而非异常处理,不同APIs有不同的处理方法。而大多数错误定义是默认的,所以进行异步编程时需要花一定时间去了解。生成器则提供了新的处理方式。

Q.async()是一个实验性的类似于同步代码的异步代码生成方法,请看代码:

// Synchronous code to make some noise.function makeNoise() {  shake();  rattle();  roll();}// Asynchronous code to make some noise.// Returns a Promise object that becomes resolved// when we're done making noise.function makeNoise_async() {  return Q.async(function* () {    yield shake_async();    yield rattle_async();    yield roll_async();  });}

两者的主要区别是异步代码必须使用yield关键字来执行异步函数。因此生成器为新的异步编程模型带来了新的思路,更符合人的思维习惯。

写在最后

限于篇幅,生成器还有两个方法留待后续讲解,.throw()和.return()。多看官方文档多动手练习,你会发现ES6更多精彩。(译者:伍昆 责编:陈秋歌)

原文链接:ES6 In Depth: Generators

本译文遵循Creative Commons Attribution Share-Alike License v3.0 

相关阅读:

【探秘ES6】系列专栏:ES6简介

【探秘ES6】系列专栏:迭代器和for-of循环

欢迎加入CSDN前端交流群:218126086,进行前端技术交流。  

独家:前RIM大中华区总经理刘征宇,加入Appconomy 用一个API搞定一切 Segment.io为移动开发者提供便利的分析数据分发服务 TIOBE 6月编程语言排行榜:JavaScript回归前十 《Kingdom Rush Frontiers》上线后 迅速抢占27个国家游戏榜首 移动周报:85后程序员,iOS开源项目,细数7天大事件! Instagram:从Redis到Cassandra 成本节省1/4 乐元素CTO凌聪访谈:游戏引擎技术选型之王道 iOS 7的新设计并非止于外表 WWDC 2013大会10大启示:正向开发者支付大量现金 云计算大会微软专场成功举办 Windows Azure公众预览版上线 IBM全球大裁员 在美国裁员已经开始 动动鼠标,决定“中国十大优秀开源项目”的归属 为改善Flickr 雅虎收购拍照应用开发商GhostBird 让你轻松学习新代码库的六个步骤 RESTful API 设计最佳实践 谷歌11亿美元豪购Waze原因:获取数据 争本地广告市场 为什么大家都要疯狂吐槽iOS 7的扁平化设计? 伟大的程序员是天生的,不是造就的 比Hive高效7倍 Facebook推新一代查询引擎Presto 未来的存储系统设计——PMC技术交流会举行 第五届中国云计算大会PPT尝鲜:十位专家分享的架构实践 “DIY”可穿戴设备:索尼开放智能手表固件 在微软的八个月里,我学到了这些 谷歌实习生每月都拿$6000,你呢? 【第五届中国云计算大会】由瓦特变比特输出,新疆要做中亚云服务中心 应用程序扩展性实现的十宗罪 图文:看谷歌实习生的惬意生活 为移动而设计:交互设计篇 小米游戏中心月度报告:极品、神庙、找你妹 中科院:常温下的液态金属电路3D打印机 细数IE10里的HTML5特性 问题一个,请教! 增值合订本出的我心不甘 我又来提问了~前天复习是发现一道很怪异的题目~ 用activemovie控件打开一个URL,用哪个函数? 如何去掉ACTIVE MOIVE控件下面显示的几个键和进度条 c源程序。 >>>>高分求解!!!我在一个对话框中插入一个active report run time design,但程序运行时却不显示,在vb中却可以,如何解决这个问题?????? 关于sql server的安装 哪里有下载cc编译器的? 关于导出数据窗口数据的问题,明白人请进! delphi可不可以用于自动控制方面的开发呢 如何使对话框程序执行就让整个屏幕背景变黑色?? 想了解有关程序考试的一些情况? 不同系统就不可以直接电缆直接吗? 怎样使用PQMAGIC对硬盘进行调整分区 memory fault--core dumped的问题 有谁知道怎么解win98的开机密码? 用 procedure 与 trigger 、database link 能完成吗? flowerofwind,rjcludy()请回答 COM中的一个怪问题:我将::CoUninitialize();去掉后程序不出错,添上出现非法操作,是啥问题??? 请问?????? 如何在程序中播放rm格式的文件??? edit怎么用啊? JB6盘中不含 Borland Enterprise Server AppServer5.0,各位快载一个上去吧! 如何改变显示的分辨率? 那里有c#编译器免费下载?谢谢 如何在vc中播放rm格式的文件??? 那位大侠知道怎么创建并使用一个变量,每次只让一个进程访问???给个例子吧,大大大 大 delphi中怎么编写中断,获取外部设备传来的信息?急救!! 数值模拟与计算仿真,高手请帮忙! 请问:dos下图形放大算法或思路?还有.........(高手请进) 求教!!!!SOS!! --请问如何将一个BMP图形文件转成JPG图形文件,高分请教师--- 高分给出,win98的怪问题! 打印统计问题 请教 : html的javascript 中报错:document.Form1.client_name.value不是对象 VC++里面如何从文本文件中一行一行读取文件? 请问,如何用mail函数批量发送邮件.多谢. 各位请教一下,Jsp 的服务resin在win2000下是怎样配置的 各位兄弟: 有谁知道 侯杰 的 <多线程程序设计> 什么时候才能买到??? 哪里有VFP3.0下载? system.ini和win.ini的作用 怎样生成安装包,多谢! 如何在两个不同的应用程序之间拖动文本字符 请问,PTSTR 和 PSTR 有什么不同? 反对上海电信变相涨价的行为。我能不能告中国电信“违约”和“欺诈”呢。 求救!误删Office2000注册表! 生成.exe出错 在Excel中,如何让某些行不能滚动? 在--成都--程序员能拿多少--¥--???? 换了17寸纯平显示器,开心,放分. 错装PB7,不能无create datawindows的图标,全是XX,为什么? 如图所示,已知直线a与b是异面直线,直线c∩a=M,直线b∩a=N,又a∩平面α=A,b∩平面α=B,c∩平面α=C求证:A,B,C三点不共线急!大致图像是这样,可能图像不清. 过两点A、B能画几条直线?平面上有A、B、C三点,过其中任意两点画直线,能画几条? 已知三角形ABC的两边AC和BC分别交平面a于点MN,设直线AB与平面a交与点O,则点O与直线MN的位置关系如何急~~~~~~~~~~~~~ 反函数,向量,三角函数的计算公式? y=(lnx)^x·x^(lnx)的导数 在正方体ABCD-A'B'C'D'中,直线A'C交平面ABC'D'于点M,试作出点M的位置.说明理由,最好给图 有一支刻度均匀但读数不准的温度计,放在冰水混合物中示数为4℃,在沸水中的示数为96℃.用这支温度计测得烧杯中的水温是29摄氏度,则这杯水的实际温度是多少摄氏度? 经过平面内A,B,C三点中的任意两点只能画一条直线,其中正确的个数为( ) A.1 B.2 C.3 D.4 用对数求导法求下列导数函数.y=(x/(1+x)) 有一支温度计,其刻度是均匀的,但示数不准,把他插入冰水混合物中,示数为2℃,而放在1标准大气压小沸水里,示数为94℃,用这支温度计测一杯热水的示数是48℃,则这杯热水的实际温度是------. 在同一平面内有A,B,C,D,E五点,任意三点不在同一条直线上,能画()直线 磁场中静止的通电导线受安培力吗 一支温度计刻度均匀但示数不准,当把它插入冰水混合物中时,温度计示数为5摄氏度,插入1标准大气压下的沸一支温度计刻度均匀但示数不准,当把它插入冰水混合物中时,温度计示数为5℃,插入1 平面上三条直线相交,最多有几个交点?最少有几个交点?画图说明...1.平面上三条直线相交,最多有几个交点?最少有几个交点?画图说明.2.平面内四条直线相交,最多有几个交点?五条直线呢?n条直 通电直导线在磁场中受到的安培力方向是否与磁场方向平行? 已知:平面α∩β=直线l,又直线a与α有一个公共点P,试分析α与β的位置关系 同一平面内的五条直线最多有几个交点,请画图说明要图喔! 已知三角形ABC的三个顶点A,B,C及平面内一点P,若PA+PB+PC=AB,则点P与三角形ABC的位置关系是什么 直线l,m与平面α,β,γ,满足l=β∩γ,l∥α,m∈α,m⊥γ,则必有〔〕 a.α⊥γ且m∥β b.α⊥γ且l⊥m c.m∥α且l⊥m d.α∥β且α⊥γ 平面上有5条直线两两相交,可能有多少个交点?请画图表示出来. 洛伦兹力对运动电荷一定不做功,安培力对通电导线一定不做功, 求过程」一刻度均匀的温度计放在冰水混合物中时,示数为10°C;用它测一个标准大气压下沸水的温度时,示数为90°C.若用它来测得温水的温度为70°C.则温水的实际温度是____. (1)在一个平面上画5条直线,最多有几个交点?请画图说明.(2)在一个平面上画5条直线,可以有4个交点吗?如果可以,请画出所有图形;如果不可以,请说明理由. 为什么洛仑兹利不对运动电子做功,但安培力作为洛仑兹力的宏观表现却对导线做功 高数求导疑问如图,我有个疑问,df(u)/du,我觉得df(u)就是对f(u)求导,也即是f`(u),分母是du是什么意思,有什么作用,为什么要除以du? ⑴平面上三条直线相交,最多有几个交点?最少有几个交点?请画图说明.⑵平面内四条直线相交,最多有几个交点?五条直线呢?n条直线呢?⑶平面内有n个点,其中任意三个点都不在同一条直线上,那 带电粒子在匀强磁场中运动一定受到洛伦兹力作用对吗 通电导线在匀强磁场中运动一定受到安培力作用对吗RT 高数中反函数的一阶导数是这样求的,那么反函数的二阶导数怎么求? 高数求导问题为什么选C 有一支刻度不标准的温度计,将她插入冰水混合物中,读数为15摄氏度,把他插如1标准大气压下的开水中,读数为95摄氏度,如果将它插入某液体中,读书为35摄氏度,则此液体的实际提问是多少?写出 大一高数导数.,设y=y(x)由方程x^y+2x^2-y=1所确定,求y′′(1) . 高数求导的问题不知道红线部分是怎么来的 红线部分到绿线部分也不知道是怎么来的 用对数求导法求下列函数的导数 已知三个平行平面α、β、γ与两条直线l、m分别相交于点A已知三个平行平面α、β、γ与两条直线l、m相交于点A、B、C和点D、E、F,求证:AB∶BC=DE∶EF. 高数, 用对数求导法,求这个函数的导数 在同一平面内,与已知直线l平行的直线有___条,过直线l外一点M与已知直线l平行的直线有_____条.希望快点、、准确! 关于高数求导的问题能够告知这个极限的求导分子部分的求导过程,分母部分我懂,但是分子部分是怎样求导能否详细说明? 在如图4×4的方格内画△ABC使他的顶点都在格点上,三条边长分别为1/5根号125,4,根号(3²+2²) 若直线 L与平面b平行 ,直线a在b上 ,则 l与a 的位置关系是A、平行 B、 异面 C、 相交 D、 没有公共点偶A答案B,要理由啊 如图,请画图说明平面上到三角形的三遍所在的直线距离的点一共会有多少个?(任意一个三角形) 一支不准确的温度计,放入冰水混合物中时.示数-0.7摄氏度;放入标准大气压下的沸水是示数102.3摄氏度那么这支温度计-6摄氏度时,实际温度是____摄氏度.(精确到0.01摄氏度) 是初一的科学试卷中 高数小题,反函数求导. 三个平面把空间分成几个部分?画图表示各种情况.(请画图,有加赏,)6,7,8.主要是8个平面,画不来……求画,不尽感激. 用对数求导数法则求下列函数的导数 直线a、b不共面,且a⊂平面α,b⊂平面β,α∩β=直线m,则m与a,b的位置关系是 y=(lnx)^x的导数 放置在磁场中的通电导线,一定受到安培力作用.这种说法对吗 有一支温度计,刻度均匀但刻度线不准.用它测量冰水混合物的温度时,度数为6℃,用它测量1标准大气压下沸水的温度时,读数为96℃.(1)若该温度计某次测量显示温度是33℃,则实际温度为_____℃ y=lnx/(x^2+1)的导数,怎么求, 通电导线在磁场中受到安培力计算时忽略通电导体的磁场吗通电导线在磁场中受到安培力计算时导体本身也有磁场啊,这时忽略通电导体的磁场吗 若直线a,b异面,a‖α,则b与平面α的位置关系 y=lnx/x 的导数是多少 通电导线会不会受到自身产生的磁场的安培力作用?比如有两条导电滑轨,在上面横卧一根导体棒,在导轨一端通电,导体棒会不会在产生的磁场中受到安培力而运动? 有一只刻度均匀的温度计,但是在冰水混合物中,温度计显示的度数为5°c ,在一个标准大有一只刻度均匀的温度计,但是在冰水混合物中,温度计显示的度数为5°c ,在一个标准大气压下的沸水温度 经过平面上的三点中的任意两点可以画直线( )A 3条 B 1条 C 1条或3条 D 以上都不对 在同一平面内有3条直线ABC,如果A⊥B,B⊥C,那么AC的位置关系是什么,为什么要说明理由 直线a,b,c在同一平面内,a//b,a与c相交于一点M,则b与c的位置关系是 y=(lnx)^x/x^lnx的导数 求过程 对于同一平面内的直线abc,如果a与b平行,c与a相交,那么c与b的位置关系是相交还是平行?
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn