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

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

CMDN Club 27期:从儿童音乐教育到移动碎片化管理 聚焦全球移动市场——你所不知道的俄罗斯 MemSQL:号称世界上最快的内存-关系型数据库 兼容MySQL但快30倍 PC衰落 Intel转投Google挖掘移动市场潜力 移动周报:500元体感、精确到0.01毫米的Leap Motion TUP第29期:王淮、龚世海谈如何打造优秀的技术团队 一网打尽13款开源Java大数据工具,从理论到实践的剖析 从用户体验的善与恶说起,做用户爱“玩”的教育应用 三大主流开源硬件对比:Arduino vs BeagleBone vs Raspberry Pi “BlackBerry 10移动应用开发大赛”应用推荐 Java程序优化的一些最佳实践 Heka:Go编写,来自Mozilla,高效、灵活的插件式数据挖掘工具 Anchora鲁为民:PaaS是我的兴趣 次世代IDE Light Table 0.4发布 带来众多更新和改进 别再设计易碎的Web API! LinkedIn:55人支持2700位员工,2亿用户的大数据分析 Brian Krzanich是谁?这位新CEO预示英特尔未来怎样? HTML5开发者心声:浏览器兼容性成最大问题 传微软6月下旬将发布第二代Surface 7到9英寸全有 Turbulenz:HTML5 2D和3D游戏引擎开源 携程开放平台总经理夏天:内容+高转化率成就开发者 直接拿来用!最火的Android开源项目(一) Qunar 谌振宇:旅游行业的移动化如何布局? 大数据分析“铁三角”: Teradata数据仓库、Teradata Aster与Hadoop Teradata专业服务:打造行业企业的“数据科学家” Xamarin Evolve 2013:竭尽全力让C#服务iOS与Android 史上最全!57个Web框架4轮横向对比 回顾银行数据的可用性和一致性历史 Qubole:托管在AWS平台上的Hive服务 自由操作系统 Debian 正式发布7.0版本 4月份浏览器份额:IE 8仍居第一,IE 10翻番 哪位大哥有关于操作系统中文件系统设计的实例文档,(急用)谢谢。 有关asp中,后台编辑新闻时,上传多图片,如何在前台显示的问题 一定给分,初学java,请问java开发平台的比较 weblogic及EJB属于中间层的吗?( 请问SQLServer数据更新速度与系统配置之间关系的问题 问题还是没有得到解决,请csdn高手进来看看.(在线等!) 请大家帮忙~~~~~ 添加一个矩形框用什么函数,在上面添加文字、颜色呢? 拜托!请问全面学习J2EE一共要装哪些软件?谢谢! 这是我在本机上用ROUTE PRINT出来的内容,请高手们指点! 在线送分!!!谁能帮我解决分页的问题 请问有没有什么简便的方法在数组里插入一条纪录。 打印打印 如何通知一个正在Sleep(INFINITE)的线程结束运行? 小问题 c语言基础问题 上海的朋友!请进来说说如果你/*未来*/女朋友或男朋友第一次来上海,你会带他或她去哪些地方玩??有七到十天时间 请问长时间用光驱放DVD会不会损伤硬盘? 急救 vj6 中如何调用sql数据库 谁能告诉我早期LINUX内核的源代码和C编译器的源代码,哪能找到!谢谢! DB2安装问题 有谁知道北京数字证书认证中心是干吗?他们说的什么信息加密、网上作业身份识别、BGC是什么回事?跟服务器有关吗? 在SQL Server中导库时出现DLL错误,怎么回事 将int型转化为字符型用什么函数? 谁能告诉我早期LINUX内核的源代码和C编译器的源代码,哪能找到!谢谢!要多少分都给! 500分求菜单功能。 很急的问题!希望大家帮忙! jb8中类找不到了??? 请教高手:如何让label显示在text、button等的上面? 新手请高手帮忙了~~~ 谢谢~~~ 500分求菜单功能。 修改数据,提交保存老报错,纳闷~~~ 急!在RED HAT LINUX中怎么配置POP和STMP服务器? 散分呵呵 是真还是假,群众的眼睛是雪亮的! 求助:XP和2003双操作系统,XP用PQ分区后在2003里找不到? 500分求菜单功能。 treeview控件,如何让其点击结点后再从数据库中取得这个节点的下一层节点? 如何在SQL SERVER 2000导入mis.bak文件? HELP!一道规划问题的优化!源代码 虚心的小弟,散分(分不多) 在线等待!!sql 无法登陆 500分求菜单功能。 用VC写的dll在vb上怎么用? 这样的sql 怎样写 WIN2000和LINUX与APACHE的搭配的困惑 高分求助,各位进来帮一帮吧,有问题请教,急,急!!! 找不到包在线等 我就不相信CSDN没有高手,帖出代码求救!!! 在服务器端监视客户记录 怎样使用vc+soap kit调用web service,麻烦添加注解! 卧龙吟蜀国80级该用什么将 兵种选什么?卧龙吟蜀国我的武将有 廖化(黄金重骑) 斐(虎贲刀兵) 简雍(鼓) 刘表(鼓) 袁术(冲车) 孙乾(不知道用什么兵种) 张任(没练) 现在用的 什么是单倍型?单倍型是如何定义的? 种群中单倍型多说明什么我算种群单倍型中,22个样品有14中单倍型,这个正常吗/ 人的正常跑步速度是每秒4米,如果我每只脚负重100kg每秒多少如果习惯了拆下来每秒多少 Do you know ______ speaker of ______ Chinese language also has difficulty in learning Japanese?A.the,the B.a,the C./,the D.the,/分析一下好吗?答案是D这是04年江苏高考模拟题 I don't know weather you know that every chinese city almost have its own language.错在哪?如题 如果两个分数的大小相等,那么它们的分数单倍也相等( 对) 虾酱该怎么吃去青岛旅游回来买了些海货有个虾酱该生吃还是煮或者是蒸? 一亿美元是什么概念? 唐的灭亡和杨贵妃有关吗? 一亿美元等于多少人民币呀? 空气污染致癌 波兰向碳排放开刀斯诺登谋得俄网站工作禁化武组织:叙利亚已按规定销毁化学武美国辱华电视主持人称不会辞职 未答应“免费”医疗让俄罗斯进退两难 仅约3上海自贸区改革红利初显 打造宽进严管报告称撒哈拉以南地区明年经济增速将达学者解析温家宝首次出书谈教育:出身教山东菏泽回应城建局集体打牌:6名员工内蒙古调查乌兰察布新豪楼:立即停止办新一批法规今起实施 手机预装软件应报福州七街十二府物业交接闹纠纷 业主直生态摄影展引银行“活水”浇灌农村青年“创业之花清算公告湖南旅游电商平台上线运营“东山鲍鱼”有了国家地理标志台湾进入流感高峰期不该让孩子爬山过河上学樊振东直通苏州“康健一生”终身重大疾病保险上市千年红豆杉倒地两年多仍受保护墓经神之微服私访记西游之阎罗传说大明第一府道士联盟降龙耀世青春青涩档案之大学绝空纪天下召唤之王征战前线生命中的邪恶海战博物馆旅游粤晖园旅游笑翻天乐园旅游丹水坑风景区旅游南海神庙旅游龙头山森林公园旅游思金拉措旅游怒江沟72拐旅游东达山口旅游苍山洗马潭索道旅游百色起义纪念馆旅游
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn 说三道四技术文摘