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

【探秘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,进行前端技术交流。  

让针对Webkit优化的网站兼容WP8 IE10 CMDN Club 24期:互联网产品的演进之路——从QQ谈互联网14年进化史 360安全浏览器发布“照妖镜”和“网站名片”功能 Windows Server 2012实用教程:添加Hyper-V管理器 为何Google弃置GCE和GAE选择AWS? 2012移动应用盘点:乱象丛生 最佳与奇葩共舞 从1976至2013大事记,看Android未来命运 c#经典入门视频001基础知识-苏坤老师主讲 c#经典入门视频002学习两句话-苏坤老师主讲 c#经典入门视频003基础知识-苏坤老师主讲 回顾HTML5这一年:在痛并快乐中前进 学Apple,微软宣布2013上半年零售店建设计划 真羡慕他们:谷歌宣布Gmail电话明年继续免费 c#经典入门视频004变量-苏坤老师主讲 c#经典入门视频005变量的使用和命名规则-苏坤老师主讲 c#经典入门视频006输出变量的值(及赋值符、连接符、占位符)-苏坤老师主讲 c#经典入门视频007变量交换_输入-苏坤老师主讲 回首JavaScript这一年:笑里藏刀 百媚丛生 平板优先:Supercell游戏公司日收入100万美元 Mootools实现具有排版功能的页面拖拽 2012:云计算的春天 直击Strata+Hadoop World:百万雄师过大江 能携带的网络 Anyfi 150万建网络虚拟热点 又将颠覆产业?传苹果正开发蓝牙智能手表 JavaScript社区开发者调查结果 欢乐淘、求PS大神获腾讯开放平台应用创新大赛年度金奖 2012是响应式设计之年 12月28日:1903年计算机之父冯·诺依曼出生 Android木马病毒:伪装成Google Play图标进行DDoS攻击 IE10 CSS Hack 程序员技术分享:训练机器学习 SVM算法解析 VB访问SQLSERVER数据库问题 有关Win2K Pro+JBuilder5+Weblogic6+JDK1.3环境下调试jsp遇到的问题,希望大家能帮忙解答一下 求教.计算机专业的应届生怎样才可去游戏公司? 如何对APPLET存档? 请问这样一条select语句(包含compute)的查询结果怎么显示在屏幕上? 请问如何实现一个类似于工具提示的小窗口,并控制它的显示,或者怎样让工具提示窗口一直显示 请教各位高手关于对象序列化的问题! 现在很急切,多谢各位! 送分:如何求一个已打开ADO记录集中当前记录的行号或索引? enhydra4.0+jbuilder4.0+kelp4.0. 类型不匹配? 请教各位高手关于对象序列化的问题! 现在很急切,多谢各位!-- 请问这条select语句(包含compute)的结果如何显示在屏幕上? cn类型不匹配? 请问高手: 如何在VB.NET中调用象GetObject那样的函数 300分!!急急急!!各位大虾有提供关于报表的控件带源码的 请问各位大侠,怎么用批处理的方式开启一个后台服务程序? 如何对access文件加密!!!! 再次送分:如何求一个已打开ADO记录集中当前记录的行号或索引? 急!急!在用户界面线程中,如何接收其它窗口发送的消息? 我的toolbar潜入一个对话筐怎么是灰的???? :)请问:网上能不能找到破解了的Pro-e2000(中文版)啊? 关于退格键! java与C的问题,怎么办? VC里如何调用std里的operator new和operator delete 有沒辦法使成員函數只供指定的 class 呼叫! 关于DELPHI中的DBGRID控件 关于enhydra4.0+kelp4.0+jbuilder4.0。 能不能用Mscomm控制并口,如果行,应该怎样将一串ASCII值发送到并口;如果不行,能用其它方式吗?(最好能提供例程)多谢了。 求救,请教ado中有关事务的问题。 异想天开的问题???,进来就给分!!!! 请教高手,我如何将*.swf文件从网下摘下? 集线器与交换机怎样级联? 请问如何用RasDial 类似冰河“搜索主机”的功能怎么实现啊? 如何利用socket截获80端口数据?请给出源代码。 水晶报表的问题 Help的窗口 送分:关于数据库中的数据在前台显示的问题,敬请高手指教 请问一下各位PB FANS,PB中的自定义事件中的extenal选项有何作用? Label的小问题,以后给分,现在确实没分了。 测试a 有沒辦法使成員函數只供指定的 class 呼叫! 请问如何给listview添加鼠标拖拽功能,如从本视图中拖走一行? Jbuild and Visual Age for Java 只使用数据库表单如何不带环境? 为什么在Cmd.exe 下可以运行,但是在ASP里面却没有办法写进数据???斑竹怎么只提供4页的讨论内容呢?? 救急,启动winNT时候inetinfo.exe总是共享冲突,该咋解决? 如何防止内存泄漏 帮忙看诊断一下遇到的问题。 Fatal error C1010: unexpected end of file while looking for precompiled header directive是什么意思?怎么改正? 关于数据窗口 三价铁离子和硫氰根离子反应生成物用加沉淀符号吗? 就是实验题回答的那些 干燥剂(硅胶)遇水以后为什么会弹起来? 棕色试剂瓶不用棕色试剂瓶存放的是()A氯水 B溴化银 C碘化银D氟化钠 亚铁离子与硫氰酸钾反应据说生成物是蓝色的! 二价Fe和S离子是双水解还是生成沉淀 三价铁离子的硫氰根络合物能与铁单质反应吗?还有一个……Fe3+能表示Fe(SCN)3么? 月季花汁和玫瑰花汁遇白醋、肥皂、苹果汁分别变成什么颜色? 不同成分的干燥剂遇水反应是否会有不同? 初中化学有哪些实验 为什么白醋、肥皂水能使月季花汁和玫瑰花汁变色?鸡毛信急! 干燥剂遇水会爆炸吗? 初中化学的实验有哪些 硫氰酸钾和氯化铁溶液反应方程式怎么写? 干燥剂为什么遇到水会跳?干燥剂是"雅客益牙木糖醇"里面的,是透明的小圆珠,我把这些干燥剂全部防竟烟灰缸,然后加了一些茶水,它们就全部都跳了起来,它们会不会和跳跳糖的成分一样啊? 二价铁离子为什么不可与二价硫离子共存 谁有初中化学基本实验操作复习题呀? 干燥剂和水的反应.急用! 3价铁为什么和硫离子不共存?是因为氧化还原反应还是双水解?为什么?主要是为什么 1水无色,为什么结成冰变成了白色?2高空中的水蒸气是无色,为什么凝华后变成的雪是白色?3空气中是有水蒸气还是有水蒸汽? 向下排空气法的适用条件除了对气体密度有要求外,对试验装置是否也有要求?是不是只有如图的装置才能用?如果把如图装置旋转180°,是不是就不能用向下排空气法了? 溴的性质 :溴易挥发,应_____保存.在盛溴的试剂瓶中,需要在瓶中加一些____,以减少_____.碘易升华,应_____保存 高中保存在棕色试剂瓶的所有药瓶,最好加上见光分解的化学方程或其他原因 为什么瓶子里冻的水变成冰是白色,而不是透明的··· 有关碳酸氢钠的分解碳酸氢钠为什么只有在固体时受热才分解?液体不行?液体和固体碳酸氢钠都是以离子形式存在的呀?请问在水溶液中碳酸氢钠可以分解吗? 证明空气存在(用家中日常物品) 彩色的水冻出来的冰为什么是白色或透明的?冰可能是彩色的吗?望正解,科学理念之类的. 碳酸氢钠受热分解固体50℃以上开始逐渐分解生成碳酸钠、二氧化碳和水,270℃时完全分解.如果持续加热,温度控制在50-100度,他能不能完全分解我把碳酸氢钠放在 白酒瓶盖(金属的) 里下面 初中化学人教版有哪些家庭小实验 三价铁离子不能跟哪些离子共存要全一点的 硝酸银要保存在棕色试剂瓶中,否则见光分解,方程式? 家庭如何购买初中化学实验仪器 碘离子为什么不能与三价铁离子大量共存? 在碳酸氢钠分解反应中.生成的碳酸钠会溶解到生成的水中吗 三价铁离子、硝酸根离子、氢离子在水溶液中能否大量共存? 字数不要太多,浓缩才是精华,要分类说明,最好有口诀. 1.描述点燃拉住后火焰的颜色(从上倒下,从外倒内)2.蜡烛燃烧过程中的现象3.所观察到的其他一些现象 有哪种无色透明化学试济遇水显颜色? 钠,铝,硫,氯离子半径谁大谁最大,谁最小 见光或受热易分解或挥发的实际应盛放在------色瓶中,放置在---- 用什么化学物质,平时无色,见水可显黑色呢 正三价铝离子和负二价硫离子的离子半径哪个大? 有的化学试剂见光变质,要用有色玻璃瓶盛装.棕色,黄棕色,黑色各盛什么试剂?为什么? 笨铵皮为什么遇水颜色变深 . 钠离子,镁离子,铝离子,氯离子,硫离子等半径由大到小顺序排列?为什么? 图中反应装置的反应原理是什么?请问图中这套装置可以用来什么方法制取何种气体?请把各仪器中所装药品一一指明,并指出反应时它是如何产生的(例如:长颈漏斗中的"a"流到U型试管中,与试管 硫氢根与碳酸氢根是否反应H2S+(CO3)2-==HS-+(HCO3)-剩下的不继续反应了吗 初中化学家庭小实验要有过程 为何硝酸见光易分解就应放在棕色试剂瓶 碳酸根和碳酸氢根反应的离子方程式 Fe(OH)3溶于氢碘酸的方程式怎么写?碘离子会不会把3价的Fe的铁还原成2价?Na2S2O3溶液中通入足量的氯气化学方程式怎么写?氢氧化铝中和胃酸的方程式怎么写?过量SO2通入NaOH溶液中化学方程式NaNO2 可以操作化学实验的动画可以用鼠标移动仪器那种的! 二价铁和碳酸根,碳酸氢根,亚硫酸氢根,偏铝酸根反应的离子方程式 “蛋壳溶于食醋放出气体”这个实验谁能说的详细一点啊 AgNO3固体见光或受热易分解,故用棕色试剂瓶保存.AgNO3受热分解,放出的有刺激性气味的气体可能是()放出的有刺激性气味的气体可能是( )A.SO2 B.NO2 C.NH3 D.N2 二价铁和硫氰酸钾反应有什么现象?注意,是”二价铁” 氧化还原反应Fe+S==加热==FeS,书上强调用干燥的试管当反应器皿,为什么要干燥?想不通~ 为什么存放硝酸银溶液用棕色试剂瓶?还有哪些存放在棕色试剂瓶? 硫氰酸钾与三价铁离子反应有无沉淀生成能在溶液中共存吗? 二价fe离子水解吗?
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn