为什么80%的码农都做不了架构师?>>>   

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

你是如何遍历数组中的元素的?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 

转载于:https://my.oschina.net/1pei/blog/520584

【探秘ES6】系列专栏(二):迭代器和for-of循环相关推荐

  1. ie模版字符串_【探秘ES6】系列专栏:模版字符串

    [探秘ES6]系列专栏(四):模版字符串 为什么80%的码农都做不了架构师?>>> ... [探秘ES6]系列专栏 [探秘ES6]系列专栏(一):ES6简介 [探秘ES6]系列专栏( ...

  2. [js高手之路] es6系列教程 - 迭代器与生成器详解

    什么是迭代器? 迭代器是一种特殊对象,这种对象具有以下特点: 1,所有对象都有一个next方法 2,每次调用next方法,都会返回一个对象,该对象包含两个属性,一个是value, 表示下一个将要返回的 ...

  3. RxJS 系列之二 - Observable 详解

    查看新版教程,请访问前端修仙之路 RxJS 系列目录 RxJS 系列之一 - Functional Programming 简介 RxJS 系列之二 - Observable 详解 (本文) RxJS ...

  4. ES6系列教程第三篇--Generator 详解

    一.什么是Generator 函数 先看下面的Generator函数, function* helloGenerator() {console.log("this is generator& ...

  5. ES6 系列之 let 和 const

    块级作用域的出现 通过 var 声明的变量存在变量提升的特性: if (condition) {var value = 1; } console.log(value); 复制代码 初学者可能会觉得只有 ...

  6. ES6 系列之 Babel 是如何编译 Class 的(上)

    前言 在了解 Babel 是如何编译 class 前,我们先看看 ES6 的 class 和 ES5 的构造函数是如何对应的.毕竟,ES6 的 class 可以看作一个语法糖,它的绝大部分功能,ES5 ...

  7. 「刘一哥GIS」系列专栏《QGIS入门实战精品教程(配套案例数据)》

    「刘一哥GIS」系列专栏<QGIS入门实战精品教程(配套案例数据)>全新上线了,欢迎广大GISer朋友关注,一起探索GIS奥秘,分享GIS价值! 本专栏以实战案例的形式,深入浅出地介绍了Q ...

  8. 23篇大数据系列(二)scala基础知识全集(史上最全,建议收藏)

    作者简介: 蓝桥签约作者.大数据&Python领域优质创作者.管理多个大数据技术群,帮助大学生就业和初级程序员解决工作难题. 我的使命与愿景:持续稳定输出,赋能中国技术社区蓬勃发展! 大数据系 ...

  9. 大白话,讲编程之《ES6系列连载》汇总,再也不用翻历史消息了

    想翻看以前的ES6系列章节,老是要查看公众号的历史消息,特别是在地铁里没wifi的时候,每次页面切换都要load很久,相当麻烦. 别怕,最懂你们的前端君又来了,来一篇完美的汇总,你要的ES6,都在这里 ...

最新文章

  1. python常见错误集合
  2. 软件工程 团队博客作业 如何评价个人在团队中的绩效
  3. mysql解压包安装linuex_CentOS下安装Apache,php,Mysql
  4. remote: Incorrect username or password ( access token )
  5. VS2005中Build顺序的设定
  6. 详解如何实现最基本的AJAX框架
  7. OCP-1Z0-042-V12.39-47题
  8. Oracle函数--合并,替换,拼接,截取,查找
  9. 我的世界服务器领地怎么无限大,我的世界:Minecraft都市传说,MC无限大?让我们一起寻找边界吧...
  10. 大学四年零基础自学Java的路线
  11. 计算机系统导论与计算机导论,计算机系统导论之学习心得
  12. Python基于HRHet的跌倒检测系统(源码&教程)
  13. SpringBoot中@Pattern注解对时间格式校验
  14. win10系统启动wifi服务器,windows10系统下开启wifi共享的两种方法
  15. IMU、AHRS、VRU和GNSS、INS
  16. 智能家居新体验:“小摩凳”足部按摩器上架小米有品
  17. FPGA Implementation of BPSK Modulator and Demodulator
  18. 游戏黑客圣经GHB1学习笔记 part4(16-20)
  19. easyUI折叠表格-默认展开操作-去除扩展符号(+)-清除滚轮--实例加效果图
  20. python代码风格指南:pep8 中文翻译

热门文章

  1. Python如何读取文件
  2. 2018/8/9 MultiU 6 并查集+dfs,反向建边提高查询效率 !!! / 最大字段和n维(降维)/ 状压+中途相遇法...
  3. docker(iptables)目标地址转换,运行中的容器映射端口
  4. 整合百度UEditor上传图片到阿里云OSS
  5. 微信小程序常见错误及基本排除方法
  6. 它是最神秘的黑客组织:来自战斗民族 专黑美国
  7. 牛客网 --java问答题
  8. javax.servlet.jsp.PageContext cannot be resolve...
  9. Linus Torvalds:回顾Linux20年
  10. springboot的IOC依赖注入与控制反转-举例(转载+自己整理)