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

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

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

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

你是如何遍历数组中的元素的?20年前JavaScript刚进入视野时,你应该是这样写的:

for (var index = 0; index < myArray.length; index++) {     console.log(myArray[index]); }

直到ES5中原生JavaScript中添加了forEach方法:

myArray.forEach(function (value) {     console.log(value); });

语法上简洁了一些,但是它有一个小小的不足:你不能用break语句跳出循环且不能在这个封闭的函数内使用return语句。

如果有一个简单的for-loop语法来遍历数组就好了。

使用一个for-in循环怎么样?

for (var index in myArray) {     // don't actually do this     console.log(myArray[index]); }

我用几个理由来说明这并不是一个好主意:

  • 数组的索引值index是String类型的“0”,“1”,“2”等等,而不是Number类型。当你进行算术运算时(“2”+1==“21”)也许并不是你期望的结果,所以运算前需要类型转换,这很不方便。
  • 循环体不仅会遍历数组的元素,甚至连expando属性也遍历出来了。举个例子,如果你的myArray数组中有一个叫做name的属性,遍历时就将 index ==”name”也遍历出来,这样就多了一次执行。即时这些属性在数组的原型链上是可直接访问的。
  • 最让人无语的是,在某些情况下,这段代码在遍历数组元素时顺序是任意的。

总而言之,for-in语法是被设计来遍历普通的“键值对”对象的,不适合用在数组上。

强大的for-of循环

还记得我上篇提到的ES6是向后兼容的吗。即使在遍历数组的时候,成千上万的网站使用了for-in循环。所有“修复”for-in让它更适用于数组是有必要的。ES6来解决这个问题的唯一途径是新增一个新的遍历语法。

新语法如下:

for (var value of myArray) {     console.log(value); }

恩?!从构建上来说好像并没什么改变,事实如此吗?当然不是,我们来看看for-of的葫芦里究竟卖的什么药。首先,只需要注意这几点:

  • 这是目前遍历数组最简洁和直接的语法;
  • 它避免了for-in的所有缺陷;
  • 与forEach()不一样,它支持break,continue和return。

for-in循环用于遍历对象属性。

for-of循环用于遍历数据——比如数组中单值。

其它集合也支持for-of

for-of循环不仅仅是为遍历数组而设计的。基本上所有类数组对象都适用,比如DOM NodeListS。

也能用在字符串上,它将字符串当做一个Unicode字符序列:


它也能用在Map和Set对象上。

哦,不好意思,你没听说过Map和Set?没关系,他们是出现在ES6中的新成员。有机会我们会写个完整的关于它的文章。如果你使用过其它编程语言中的maps和sets,那么你也不会有陌生感。

例如,一个set对象使用于排除重复项:

// make a set from an array of words var uniqueWords = new Set(words);

如果你想遍历你的set,很简单:

for (var word of uniqueWords) {     console.log(word); }

Map有一点不同:它里面的数据由键值对组成,所以你需要使用destructuring将“键”和“值”解构为两个独立的变量:

for (var [key, value] of phoneBookMap) {     console.log(key + "'s phone number is: " + value); }

Destructuring(解构)也是ES6的新特性,在未来博客中会有很多关于它的文章。

目前为止,你可以这样理解:JS已经有了几个不同的集合类,而且更多的集合类正在被添加进来。for-of循环语句的设计初衷就是适用于所有这些集合类。

for-of并不能用于普通的旧对象。如果你想要遍历对象的所有属性,可以使用for-in,也可以通过Object.keys(object)将对象的所有属性以数组形式返回后再使用for-of。 

// dump an object's own enumerable properties to the console for (var key of Object.keys(someObject)) { console.log(key + ": " + someObject[key]); }

深入理解

“能工摹形,巧匠窃意。”——巴勃罗·毕加索

JavaScript在ES6中所新增的特性并不是凭空而来,大多数都是借鉴于其它优秀的语言。

以for-of循环伪例,与C++、Java、C#和Python的循环语句非常类似。和它们一样,支持该种语言提供的多种数据解构和标准库。但是它也是该种语言的一个扩展点。

就像for/foreach语句在其它语言中一样,for-of的执行完全靠方法调用。像Arrays,Maps,Sets等我们提到过的对象都有一个共同点就是它们都有一个遍历的方法。

其它类型的对象也都可有一个遍历方法:任何对象都可以。

就像你可以对任何一个对象添加方法myObject.toString()让JS知道如何将对象转换为字符串一样,你也可以对任何对象添加方法myObject.toString()来告诉JS如何遍历这个对象。

例如,假设你使用的jQuery,尽管喜欢使用.each(),那你也会喜欢上在jQuery对象中使用for-of。请看下面这个例子:

// Since jQuery objects are array-like, // give them the same iterator method Arrays have jQuery.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];

好吧,我知道你会觉得[Symbol.iterator] 这样的语法看起来很奇怪。它是怎么执行的呢?使用方法名就可以了。标准委员会刚刚将这个方法命名为.iterator(),但是你已存在的代码中可能已经有了叫做.iterator的方法,那会造成命名冲突,让人傻傻分不清。因此所有标准库将其封装进了symbol,而不是使用简单的用字符串来直接命名。

Symbols是ES6的新特性,我们将在以后的博客中讨论它。目前,你所需要知道的是现在标准定义了一个全新的symbol,比如Symbol.iterator,为了保证与已存在的代码不存在命名冲突,所以这个代价就是语法看起来有点奇怪。

为了这个优秀的新特性的向后兼容性,这点小代价也就微不足道了。

迭代器对象

从现在开始你再也没有必要为自己写一个迭代器对象了,这个我们在下篇文章中再来讨论。但是出于完整性的考虑,让我们先来看看一个迭代器对象是什么样子的。(如果你跳过这一节,你会错过很多有趣的技术细节哟)。

for-of循环开始于对集合的[Symbol.iterator]()方法的调用。它会返回一个新的迭代器对象。任意一个有.next()方法的对象都可以被称作迭代器对象;每次执行进入循环时,for-of方法将会用.next()方法。例如,下面是一个我所能想到的最简单的迭代器构造:

var zeroesForeverIterator = {   [Symbol.iterator]: function () {       return this;    },    next: function () {        return {done: false, value: 0};    } };

每次当.next()方法被调用的时候,它会返回相同的结果,告诉for-of循环:(1)我们还没结束迭代;(2)下一个值是0。这意味着,(value of zeroesForeverIterator) {}将是一个无线循环。当然,一个真正的迭代器并不会这么简单。

迭代器的设计,伴随着.done和.value属性,从表面上来看似乎和其它语言中的迭代器不太一样。在Java中,迭代器将.hasNext()和.next()区分为两个方法。在Python中,它只有一个.next()方法,当没有下一个值时会抛出StopIteration 。但是从根本上来说,这三种方法返回同样的信息。

迭代器也可以实现一些可选方法,比如.return()和throw(ext)。在for-of循环中,当遇到异常或者break和return语句时可以调用.return()方法提前退出循环。迭代器可以通过实现.return()方法来清空变量或释放当前资源,大多数迭代器对象是使用不到这一点的。.throw(exc)是一个特殊的例子:for-of完全使用不到它,我们下次再来讨论。

现在我们已经了解了所有的基本细节,我们可以写一个简单的循环并重写它的底层方法调用部分。

先写一个for-of循环:

for (VAR of ITERABLE) {     STATEMENTS }

下面这段代码使用简单的底层方法和几个简单的变量来实现同样的功能:

var $iterator = ITERABLE[Symbol.iterator]();var $result = $iterator.next();while (!$result.done) {  VAR = $result.value;  STATEMENTS  $result = $iterator.next();}

这段代码并没有体现出.return()操作。我们可以添加进来,但是我认为认清它的执行过程比阐明它更重要。for-of的使用起来很简单,但有很多看不见幕后的工作。

我什么时候才能使用它?

当前所有的Firefox releases版本都支持for-of循环。如果你想在Chrome中使用,到chrome://flags设置“Experimental JavaScript”为“开启”即可。微软的Spartan浏览器支持它,但是IE不支持。如果你想要在Web中使用这些新语法且不用考虑支持IE和Safari,你可以使用Babel或者谷歌的Traceur这样的编译器将你的ES6代码转换成兼容性友好的ES5。

在服务端,你不需要一个编译器——你可以在io.js(基于Node,是一个不错的选择)中使用for-of。

(更新:在Chrome中默认是禁用的,这个被我忽视掉了,感谢Oleg 指出。)

讲完啦!

我们今天的计划都完成了,但是我们对for-of循环的学习还没结束。

ES6中还有一个和for-of完美结合的新对象。我之所以没提到它是因为它是我们下次的主题。

我认为它是ES6中最神奇的新特性。如果你之前没在像Python和C#这样的语言中使用过它,一开始它可能会让你感到难以置信。无论在客户端还是服务端,这是写一个构造器最简单方法,对于重构很有用,它有可能会改变我们写异步代码的方式习惯。

下次将一起深入ES6的generators 。(译者:向渝 责编:陈秋歌)

原文链接:ES6 In Depth: Iterators and the for-of loop

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

相关阅读:

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

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

豌豆荚:“应用内搜索”是打通移动互联网最具竞争力的入口 苹果发布会后的冷思考,64位芯片为开发者带来了什么? 中兴Geek评测:高性价比的英特尔处理器智能机 SAE的资源、安全隔离与Container 平板电脑悬了 Phablets或成为未来移动设备的主流 拿什么拯救你:黑莓今年将裁员4500人 推荐10款免费的在线UI测试工具 最好的Java IDE之争:Eclipse PK IntelliJ IDEA Intel发布E5 2600 v2处理器 开放硬件监控信息 XP寿终大限将近 微软再次呼吁用户尽早“分手” Dropbox CTO:离开办公室就焦虑的技术宅男 看雪学院“走进企业看安全”活动百度站落幕 九大设计技巧+作品赏析 激发你的创作灵感! 排名前十CEO的工资条,你怎么看? 麻省理工TR35之IT界年轻有为创新者(下) Storm的“翻版”:LinkedIn开源实时数据处理系统Samza 呼吸监测耳机:一个在“呼吸”上做文章的可穿戴设备 谷歌7年210亿美元的基础设施建设,及可供17万家庭使用的风电 Touch ID很安全?德国黑客宣布已绕过苹果指纹识别系统 纽约警方鼓励用户升级iOS 7 你想好了吗? Android开发者不可或缺的四大工具 Mozilla开源TogetherJS:让网站拥有实时协作功能 可穿戴技术专家Jawbone UP向所有开发者开放API 18款在线代码片段测试工具 Gartner咨询公司研究副总裁彼得&#183;福斯特布鲁克:互联网安全新兴威胁与挑战 美国智库战略与国际研究中心(CSIS)詹姆斯&#183;刘易斯:网络安全神话、传说与现实 云安全联盟中国分会理事赵粮:建设可信的云生态环境 Web前端优化最佳实践及工具集锦 2013中国互联网安全大会(ISC)9月23日隆重举行 科技界最聪明的人:Facebook首任CTO激情燃烧的岁月 继乔布斯时间胶囊出土 其儿时的家或成历史遗迹 请问上海业成软件公司怎么样? 有关局域网的基础理论问题请教! tomcat 3。1--4。0 乱码问题 高手帮忙,搞不懂的问题!(在网页中使用ActiveX控件,并用VBScript读取本机文件) 疑问:中国编程人是否年纪太大? 在查询的记录集里怎么增加序号?什么函数? 有关局域网的基础理论问题请教! listview用法问题,急用! 《C++ Primer 3e 題解》簡體中文版 出版了没有呀??? 我把paradox数据库引擎BDE改为ODBC,用户名和密码是什么? VC控件问题 急啊,急啊! 急,关于打包问题 当用查询控件时,返回多个结果,该怎样区分啊?!谢谢! C#里可以实现类似VC++的消息响应吗? 没有人回答吗? 如何在vb中把bmp格式的图片转成jpg或gif的格式 请问在asp中怎么输出显示datetime时间和binary类型的图片? 有关unicode 在调试时,高手指点 非常简单的问题,但我不会,也想不出来,在ms sql server中如何获取特定日期后一个月的日期? 谁对identity column 有研究呀?请进来帮个忙。。 大家好:如何用Delphi报表打印信封,还要有邮政编码,就是像个信封。谢意! 正规表达式,痛苦! 很奇怪的事情!!!month calendar使用的问题!!!!!!! 得不到month calendar控件选中的日期?? vb有vss,delphi有什么? VB7.0与VB6.0不兼容 关于ole编程的问题 来新公司一月了,遇到一个问题,请大家帮忙分析! 数据复制的问题,高分求救! 如何获取TitleBar的尺寸? 创建文件夹的函数及检查是否存在某文件夹的函数?(手册上没有) qqq pcAnywhere操作不能刷新的问题?高手来解救我吧!! 请帮我分析一下为什么会出现这样的错误提示:Access vidation at address 004a36B2 in modale'**.exe'read of address FFFFFFFF CTime和CTimeSpan的使用问题!!!很奇怪??????? 我在写Tuxedo服务程序时,在VC++环境下编译连接时发生以下错误。 关于PDF文件(高分奉送) 来新公司一月了,遇到一个问题,请大家帮忙分析! 谋杀——转贴 打安装包时,提示某些dll过期(很多),怎么办呀? 出生年月与年龄的问题 大家帮帮忙!!!!!!!!!!! 我的天啊!CListCtrl不允许设置行间距和字体大小吗? 如何在40G的硬盘(maxtor)上安装nt4.0 100分(我全部的分),加速,代码优化,JPEG 求救 如何编代码自动创建NT的账号、密码(用什么API实现) 大家看看,我在做一个Messagebox的提示信息时的提示!!!!!奇怪,.net真奇怪 关于计数统计的问题 查某一个人全部贴子的方法。 怎样建立无盘工作站?? pcAnywhere操作不能刷新的问题?高手来解救我吧!! 用定积分求直线y=x,x=1,x=2,y=0所围成梯形的面积 一批零件,甲独做6小时完成,乙独做8小时完成.现在两人合做,完成任务时甲比乙多做24个? 请高手说文解字“country”为什么即是“国家”又是“乡下”这个词的来源是什么,拉丁文还是法语还是什么?为什么国家和乡下这两个毫无关联的意思都用这个词表达,恐怕只能从词源和原始意 小林有面值5角和8角的邮票各两枚.他用这些邮票能付多少种不同的邮资?一一列举出来,分好类 有没有关于外出的80词的英语作文? country怎么用是urban的意思?有时是国家,有时是乡村~怎么分! 给远方的同学写信交朋友,给我个地址和姓名,要男的 求一篇社区活动感悟,200字左右内容为劝导清理楼道,收集废电池,垃圾分类 在长12厘米,宽7厘米的长方形里画半径为1厘米的圆最多画多少个? 一辆汽车从甲地开往乙地送货,第一小时行了全程1/4,第二小时行了84千米,这时已行程与全程的比是1:3.甲、乙两地相距多少千米? 小明有20分和30分的邮票各两枚,他用这些邮票能付多少邮资? 假设你是李明,上个星期天你和你的同班同学到公园里快乐的度过了一天.请你给你的笔友Jim写信,词数:80左右提示语:sunny,classmate,go,have a good time,leavefor,on the way,in the park,have lunch,delicious,then,t 小汽车从甲地到乙地平均每时行84千米,用了3.6时,货车从乙地到甲地用了5.6时,货车平均每时行多少千米?(用方程) 本人初二男生,想与年龄相似的男生写信交友,真心坦诚的男生们留下地址或写信绐我:广东省肇庆市怀集县怀城镇第一中学初中部初二A2班林铭豪. 社区活动后的感想 (高中)800字 防静电胶管如何接地 小明有面值5角.8角的邮票各有两枚,他用这些邮票能付多少种不同的邮资? 李明、张华、刘明艳、赵倩、朱亮5位同学组成一个学习小组,星期天集中到其中一位同学家里他们各家之间的距离如下表所示(单位:cm)李 张 刘 赵 朱李 0 张 620 0 刘 780 580 0 赵 450 480 840 0 朱 810 防静电POM板,防静电POM棒,防静电尼龙板,防静电尼龙棒哪里有卖?质量要好 请以“我的初中生活感受”,给小学同学写信 在长为1.25米,宽为0.8米的长方形纸板上,最多能画多少个半径为20厘米的圆. a 12 b 10 c 6 甲,乙俩地距离是m千米,一汽车从甲地开到乙地,汽车速度为a千米/时,现走了一半路程,他索性的时间为? 公交出行的好处英语作文 甲乙两人合作一批零件,计划6小时做完,现在由乙先做1.5小时后,甲再加入合做,完成任务比计划多用5分之3小时,已知甲每小时做54个零件,这批零件一共有多少个零件不要给我像这样的答案:乙1. 华华有2枚3角和3枚5角的邮票,用它们可以支付几种不同面值的邮资? 公交车用英语咋说? 甲乙两人合作一批零件,计划6小时做完,现在由乙先做1.5小时后,甲再加入合做,完成任务比计划多用5分之3小时.这批零件由甲独做需几小时完成? 含有练字练意的意思的词语要3个 无人售票公交有什么好处-英文作文 甲、乙两人合做一批零件计划6小时做完现在由乙先做1点5小时后甲再加入合做完成任务比计划多用3/5小时,已甲每小时做54个零件,这批零件一共有多少个? 谁能几张平面构成渐变构成的作业 良知 阅读答案尼娜没有做好家庭作业.她拿定了一个逃学的主意.要是人家都在工作,在上学,就她提着书包在街上晃荡,别人一眼就能看出她是在逃学的.为了不让熟人发现她逃学,她悄悄拐进了 甲、乙两人合作一批零件,计划6小时做完,现在由乙先做1.5小时后,甲再加入合作,做完任务比计划多用五分之三小时,已知甲每小时做54个零件,这批零件一共有多少个? 平面构成渐变作业怎么做 良心如枕阅读答案 甲乙两人和做一批零件计划6小时完,现乙先做1点5小时后,甲乙和做,完成任务比计划多用5分之3小时 曲线y=cosx,x∈【0,3/2π】 与坐标轴围成的面积.好像用定积分做 《良心如枕》阅读答案午后,倚于床头闲翻杂志,看到了一个句子:“清白的良心,是一个温柔的枕头.”细细体味这个句子让我想起一件事来.这件事是发生在我母亲身上的,夏天晚上我们在院中 跪求一篇1500字以上的社会实践体会活心得(关于春节间打扫街道) 跪求一篇1500字以上的社会实践体会活心得(关于在一工厂打扫的体会与遐想) 曲线y=cosx及直线x=0和直线x=π所围成区域的面积为.用定积分形式表达 求一篇以“我的梦,中国梦”为题的征文 要原创. 社会实践报告 1500字 来两篇 求给力! 定积分的应用,曲线y=e^x * cosx,0 主题 :我的梦.中国梦 征文1阐述自己对“中国梦”的认识和畅想,书写自己的美丽梦想,表达自己爱祖国、爱家乡……的情怀.2.内容积极向上,事例贴近自己的生活.(诗歌可以不写事例)3.体裁 一张长10厘米,宽8厘米的长方形纸板上剪半径是1厘米的圆,最多可剪多少个? 一个外国小朋友手中有4张3分邮票和3张5分邮票,请你帮他算一算他用这些邮票可以组成多少种不同的邮资? 在极坐标系中,求点p(2,-π/6)到直线L:Psin(θ-π/6)=1的距离要程 社会实践论文3000字 有的谢谢了额 画平面构成怎样表达某种情绪? 把底面积相等的一个圆锥形铁块先后浸没在盛水的长方体的容器中.放入圆锥形铁块后,水面上升2厘米.放入圆柱形铁块后,水面又上升了2厘米.已知圆锥高12厘米,圆柱高几厘米?有一块长15.7厘米 再长是10厘米、宽是7厘米的长方形纸板上最多可以剪多少个半径是1厘米的圆? 求这幅图的作者,图的名称,以及图的平面构成 求几篇社会实践活动文章 要求3000多字 字多了些 怎样能画出一个表现出紧张的平面构成?老师布置话一个平面构成的图样 要表现出紧张的感觉 或者说有没什么图样 字母能够表现? 文化是什么 文化在哪里 阅读答案 country在什么时候指农村什么时候指国家? 平面构成!高手来看这个作品是怎么画出来的,具体点呀 蚂蚁的文明阅读答案 速回 country在这里是国家的意思?还是乡下的意思?I live in the country.
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn 说三道四技术文摘