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

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

iOS开发者讲述在Google工作的三个月 GitHub历史上最糟糕宕机事故回放及反省 疑因竞争 谷歌有意让地图与WP手机不兼容 移动游戏开者必看:海外VC最关心什么? 淘宝UED:随侃设计师的个人素养 TIOBE 2013年1月:不负重望 Objective-C再次赢得桂冠! 大数据:商业或技术的挑战? 开源移动统计:Cobub Razor近期版本大升级 无人机应用,为何屡遭苹果拒绝 2013年Java继续火的五大理由 Rails所有版本都有SQL注入漏洞?其实没那么严重 如何设置Windows Server 2012 NTFS权限 智能手机大局已定 HTC难扭转乾坤? 比谷歌手表更酷!基于大数据分析的睡衣 众投资金:改变了移动游戏开发的一切一切 这些科技产品和革新或在今年“横空出世”?! 现代Objective-C七宗罪 Google工程总监Ray Kurzweil意欲打造“虚拟朋友” 惠普开源JavaScript框架Enyo更新:支持桌面和移动平台 分析:三星或将成为科技行业第五巨头 是真的 诺基亚真有可能推Android手机 如何打造IE10的指尖触碰式用户体验 SUSE全球OEM联盟总监:为何SAP HANA只选择SUSE? 推荐2013年最佳PHP开发框架 Patrick Wyatt:代码没问题 程序却有bug? NoSQL的可靠性及扩展操作 最新Skype加密技术:“无声”通话能躲过FBI监听 谷歌锁死SDK,能阻止Android碎片化吗? KitCam团队专访:为应用做加法也能雄踞榜首 谷歌哭了:Replicant 4.0 SDK发布搅乱大局 忍者神龟与禅宗启示:如何突破移动广告困境 页面控制问题(立刻送分) 菜鸟的问题 还是那个,显示前能是HTML文件,后台是ASP文件! 哪位高手有EPOC软件开发的中文资料? BCB6的序列号是什么? 第四次问ado问题,很急,星期一要交,谁能帮个忙呀 sos 請教:運行時當ListView失去焦點后,就不知道當前記錄在什么位置!如何才能做到失去焦點后,當前記錄條顯示灰色? 现在的女孩很弱智!!! VC当中有没有反汇编?能解释一下么? 大家来评评是否假东西? 关于菜单 請問 如何在IE中实现设置用户的分辨率!在线等待,急急急!!! 谁能提供XP和《Peopleware》的书下载。 怎么用C编算24的程序? 如果我想给date grid控件加一些功能,比如加一个复选框,可以判断哪项被选中,该怎么加? 分区问题 sos 请问如何在自己的软件中加入注册功能? 请教一个问题 请问怎样使动态创建的控件响应一个事件 windows编程高手请进 我真惊了,小弟刚用VB6,请问,VB6怎么会有乱吗问题?怎么解决!各位大侠请帮忙!! 如何使一段程序停止运行,并自动释放相应的堆栈? 请问西安哪儿能买到《The C++ programming Language》? 谁能告诉我#include <fstream>和#include <fstream.h>的区别? 条件?返回值1:返回值2???? 在CEDIT的CHANGE事件中怎么不可以用CEDIT::REPLACESEL()?? 打印高手请进 谢了 简单的键盘消息! 如何在表里添加列? dll调用的问题 请知道NotesSMEI的高手帮忙 奇怪错误 如何用ATL创建一个全局COM(只启动一个实例)供所有客户端使用? 如何修改一个域的值?用@SETfield吗? 怪! 怪! 怪! 为何存储不上数据???(急) 我真惊了,小弟刚用VB6,请问,VB6怎么会有乱吗问题?怎么解决!各位大侠请帮忙!! 急救!!用pb写登陆界面出现的大问题! 欢迎大家来! 急!如何在一个form窗体里面来移动线条,就象类似于画基本的电路图那样,谢谢高手的指教!!! 哪儿有<<新编计算机绘图>>下载啊? 给高分 急!如何在一个form窗体里面来移动线条,就象类似于画基本的电路图那样,谢谢高手的指教!!! 可以用网页文件重新启动机器吗? 高手请看看!!!如何用ATL创建一个全局COM(只启动一个实例)供所有客户端使用? 哪里能下载到vs.net正式版?(100分) pascal 谁知道有没有创建Service的好工具? 谁来介绍一下CORBA ? 请教ODBC SQL中 CONVERT的用法? 220v 300w的电器用在美国110v的电源上会损坏吗? 能不能用湿抹布擦镜子 擦玻璃时用抹布打湿后,再用旧报纸擦拭,玻璃显得比抹布擦的还要干净,是为什么呢? 如果适用于220v的电器插在110v的电源上会怎么样,如果反过来110v的电器插在220v的电源上呢?哪种会把电器烧坏?请详细解释一下,谢谢! 高中化学,铝热反应操作的描述是? 教室里一面墙上有三扇窗户,清洁窗户玻璃时,先用湿抹布清洁要2分钟,再等4 分钟,最后用干抹布清理一次,要1分钟.问清洁完3扇窗户要几分钟?怎样安排呢? 单项220V用电器,可否接在110V电源上.需看补充!交流110V电源,取A,B两项,双火线形成线电压220V ,可否用于普通单项220V用电器.如可用,原理是什么?为什么不用零线也可形成回路? 高中化学里的铝热反应的实验操作中为什么要加氯酸钾?目的是什么呢? 玻璃为啥用抹布擦会花 交流发电机 电流方向改变.我怎么感觉是转一周变4次.比如开始时线圈是与磁感线平行,磁通量为0,转到与磁感线垂直,磁通量最大,然后从最大变到最小,线圈与磁通量平行(转了半圈).然后又 铝热反应实验中氯酸钾的作用是什么? 直流发电机能改装成交流发电机吗?怎么弄?要简单点的,还有,交流电动机能作交流发电机吗? 为什么交流发电机电流变化为什么交流发电机电流不断变化,而且书上说当线圈与磁感线垂直时就无感应电流,为什么?既然都垂直了那一定切割磁感线,为什么还无电流呢 能与酸反应又能与碱反应生成两种盐和水的氧化物是两性氧化物还是不成盐氧化物 化学方程式的书写中,我们通常用什么开关的符号表示需要“加热”? 简要说明为什么交流发电机发出的电流,方向是周期性变化的说具体 四四冲程汽油机的曲轴的转速与活塞的转速有什么关系?比如说 曲轴的转速是600r/min,活塞的行程是20cm 化学方程式中,催化剂与加热的符号哪个在等号上面?求教,只是格式问题 阴离子检验的试剂顺序,为什么?有何用处?比如为什么CO3 2- 是先BaCl2溶液后稀盐酸,比如 交流发电机表示电流的是什么人们在日常生活中使用的工频交流电是由发电厂的发电机生产的,发电机中形成电流的是 a自由电子 b正电荷 c正、负离子 d电子,空穴对 现有4摩尔铝及足量稀盐酸和稀氢氧化钠溶液,欲将铝全部转化为氢氧化铝,所需盐酸与氢氧化钠的物质的量之和最少应为? 谁能教我把12V的电源调升到24V的? 就是说把汽车原来的12V电源调升到24V,因为有一个家用功放用220V的.音效很好,想改到汽车上用,可是汽车上原本的12V电源电压不够,影响了功放的效果.麻烦各能 植物是不是夜间吸收氧气同时吐出二氧化碳?那样,室内的植物不是夜间吐出二氧化碳,对身体有害了?谁能支招室内放什么植物好? 氧化铝和碱反应为什么不能生成氢氧化铝沉淀(碱少量) 跪求...一氧化碳还原氧化铜属于什么基本反应类型?氧化还原反应不是基本反应类型,属于化合反应吗?可是不符合化合反应的概念..四种基本反应类型都不符合...属于什么基本反应类型? 植物白天 吸入二氧化碳,吐出氧气.晚上植物吸入氧气,吐出二氧化碳是这样吗 交流发电机和直流发电机的区别和联系.直流电动机和交流电动机中都有换向器吗? 家用功放能否改为汽车功放(家用的+-电源) 汽车电源如何充电放电 直流发电机和交流发电机有什么区别?为什么书上说“直流发电机和交流发电机发出的电都是交流电”? 一氧化碳还原氧化铜是什么基本反应类型 交流发电机 是不是转一圈就是一个周期性变化 一圈改变两次电流方向?也就是一个周期性变化改变两次电流方向?直流发电机 是不是有了换向器 电流方向不改变 但大小是不是会变化 交流 直流发电机发出的交直流电是取决于有无铜半环换向器吗?是因为第一张图有换向器吗 怎样把音响100V电源改为220V?想把原装JVC卡座的110V电源换成220V的, 交流发电机 电流方向改变.我怎么感觉是转一周变4次.比如开始时线圈是与磁感线平行,磁通量为0,转到与磁感线垂直,磁通量最大,然后从最大变到最小,线圈与磁通量平行(转了半圈).然后又 交流发电机与直流发电机的区别 一氧化碳和氧化铜的反应类型 控制氢氧焰来焊接和切割金属焊接时应使氢气过量,切割时应使氧气过量对吗?为什么? 中国环境日是什么时候?主题是什么? 给汽车功放配个电源 壹号电厂的放电速度,怎样,快吗, 为什么交流发电机供给外部电路的是直流电如题 汽车上如何装220V音响 什么是铝热反应? 用湿抹布擦过的黑板,过一会就干了,这是由于水_变成了_. 哪些是适合卧室摆放并在夜间吸收二氧化碳的植物?什么植物可以为夜间的卧室补充一下氧气,并产生点氧负离子什么的?总之是适合放在卧室的?尤其是冬天,开着窗户冷,关着窗户一夜睡下来,屋 铝热反应是什么 为什么干抹布上滴了水以后不会立刻变湿? 植物一直吸收二氧化碳吗 用湿的抹布去擦冰箱的冰凝格时,抹布不时被冰格粘住,这是为什么呢 为什么干抹布不如湿抹布吸水性强? █哪种植物晚上吸收二氧化碳的能力最强███████████████ 用湿的抹布去擦冰箱的冷凝格时,感到很费力,抹布不时被冰格粘住是为什么呢快啊!~~!很多分给你们 交流发电机的输出特性有什么? 电刷可以改变电流方向,那干嘛还要换向器? 用湿抹布擦冰箱的冷凝格式,感到很费劲,抹布不时被冰格粘住,这是为什么呢? 三相交流发电机两相线间电压为何为380V?有个回答是:当某相正处于的峰值电压为V时,另外两相的电压都不是正处于峰值状态,而只有峰值V的0.732倍.如果将这两相电源串联起来,有效电压就是: 氢气还原氧化铜和一氧化碳还原氧化铜属于同种反映类型吗? 有买过汽车应急电源的吗?什么类型的比较好,急用的! 直流发电机和交流发电机输出的是什么电?产生的是什么电?那产生什么电呢?
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn 说三道四技术文摘