2019独角兽企业重金招聘Python工程师标准>>>

迭代器和for-of 循环

你是如何遍历数组中的元素的? 二十年前,当 JavaScript 被发布的时候,你可能是这么做的:

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

从 ES5 开始,你可能使用内置的 forEach 方法。

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

这样是比较短一点,但是其也有一个小缺陷:你不能通过使用一个 break 语句以退出循环或者使用 return 语句从封闭函数中返回。

如果在数组元素上只有一个 for 循环的话肯定是很好的。

但是,如果是一个 for-in 循环的话,那是怎样的呢?

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

这将是一个很糟糕的想法,原因如下:

  • 在这段代码里面,分配给索引的值为字符串“0”,“1”,“2”,等等,而不是真正的数字类型的数字。这样使用是不方便,不符合原意的,因此你可能不希望使用字符串运算 ( “2”+1==“21” )。

  • 循环体除了访问数组中的每个元素外,还会访问数组的 expando 属性。举个例子,如果你的数组拥有的属性 myArray.name,则循环除了访问数组本身的元素外还会访问该属性值,访问该属性时 index = ”name“。甚至是数组原型链上的属性也会被访问到。

  • 最令人惊讶的是,在某些情况下,这种代码可以以任意顺序遍历数组元素。

总之,for-in 被设计用来与以字符串作为键的普通的旧的对象工作。对于数组而言,它不是那么有效。

for-of 循环的威猛之处

记得上周我承诺 ES6 不会破坏你已经写好的代码。 那么,数以百万计的网站依赖于 for-in-yes 的语义,甚至其在数组上的用法。 因此,“修复” 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 字符序列进行处理:

for (var chr of "??") {alert(chr);
}

其也适用于 Map 以及 Set 对象。

。可能你还没有听说过 M哦,我很抱歉ap 和 Set 对象。 好吧,他们是新的东西,是在 ES6 中才出现的。 我们将在后面找时间给他们做一个整体的介绍。如果你已经在其他语言中使用过 map 和 set 了,这应该不是一个很大的惊喜了。

举例来说, 一个 Set 对象在消除重复的时候很好用:

// 从一个单词数组中生成一个集合。var uniqueWords = new Set(words);

一旦你获得了一个集合,你可能愿意遍历它的内容。简单例子如下:

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

一个 Map 有略微的不同: 其数据是由一个键-值对组成。所以,你要使用解构的方法来解压键和值以使得他们成为两个独立的变量:

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

解构也是 ES6 的一个新的功能。其也是我们在博客中将要讨论的一大话题。我应该要将这些都记录下来。

到现在为止,你应该获得这样的直观感受:JS 已经有了相当多的不同的集合类, 甚至更多的还在开发中。for-of 被设计为你使用的循环语句中的主力循环语句。

for-of 在普通的旧的对象上不能正常工作,但是如果你想要在一个对象的属性上进行循环的话,你可以使用 for–in ( 本来就是它的功能 ) 或者内置的 Object.keys( ) :

// 将对象的自己的枚举属性转储到控制台for (var key of Object.keys(someObject)) {  console.log(key + ": " + someObject[key]);
}

在底层

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

ES6 的一个正火热的主题是:被添加到语言的新功能的推出毫无进展。新功能的大多数都已经在其他语言中被尝试并被证实为有效的。

for-of 循环,在其他语言也有类似的循环语句,比如,C++, Java, C#, 和 Python。和这些语言一样,其工作基于语言提供的几种不同的数据结构以及其标准库。但是,这仍然是语言的一个拓展点。

就像在其他语言中的 for/foreach 语句,for-of 完全在方法调用方面起作用。我们经常谈论的,比如数组,map,集合以及其他的一些对象,他们都有一个共同点,即他们都有一个迭代的方法。

同时,还存在另一种对象,它也有一个迭代的方法:任何你想要的对象。

正如你可以对任何一个对象添加一个 myObject.toString( ) 方法后,JS 就 突然就知道了应该如何将该对象转换为一个字符串一样。你可以对任何一个对象添加一个 myObject[Symbol.iterator]( )方法,JS 突然就知道了应该如何在该对象上进行循环迭代。

举例来说,假设你正在使用 jQuery ,虽然你非常喜欢 .each( ) ,但是你也想让 jQuery 对象与 for-of 很好的一起工作。下述就是怎样去让这两个很好的一起工作:

// 既然 jQuery 对象和数组比较类似,// 将数组的迭代方法用在 jQuery 对象上。jQuery.prototype[Symbol.iterator] =  Array.prototype[Symbol.iterator];

好吧,我知道你在想什么。这 [Symbol.iterator] 语法看上去似乎不可思议。这到底是怎么回事呢?我们从方法的名称开始说起。标准委员会可以只称这种方法为 .iterator( )。但是,你现有的代码可能已经有一些对象有 .iterator( ) 方法,这可能会使事情变得相当混乱。所以标准委员会使用一个符号,而不是字符串,作为此方法的名称。

符号在 ES6 中也是新的。随后,我们会告诉你关于他们的全部内容——你猜对了——在未来的博客文章中。现在,所有你需要知道的是,该标准可以定义一个全新的符号,比如 Symbol.iterator,同时它保证不会与任何现有代码产生冲突。需要权衡的是,这样的语法有点怪异。但对于其多功能的新特性和出色的向后兼容性,这只是一个很小的代价。

一个具有 [Symbol.iterator]( ) 方法的对象被称为可迭代的。在后续的几周内,我们将看到迭代对象的概念被用于整个语言,不仅仅用于 for-of 中,也用于 Map 和 Set 构造函数,赋值解构以及新的传播算子中。

迭代器对象

现在,有一个机会,你将永远不用从零开始实现自己的迭代器对象。我们将在下周解释原因。但为了完整性,让我们来看看 iterator 对象是长什么样的。 ( 如果您跳过这一整章节,你可能主要会缺少一点技术细节。)

一个 for-of 循环通过调用集合上的 [Symbol.iterator]( ) 方法进行启动。这个操作将会返回一个新的迭代对象。一个迭代对象可以是具有 .next( ) 方法的任意对象。 然后,for-of 循环将会反复调用此方法,即每次循环都要调用一次。举例来说,下述应该是我能想到的最简单的迭代器对象:

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

每次 .next() 方法被调用都会返回同样的结果,以告诉 for-of 循环以下两个信息:( a ) 我们还没有结束迭代;( b ) 下一个值为 0。这就意味着 for ( zeroesForeverIterator 的值 ){}将是一个无限循环。当然,一个典型的迭代器不会这么的微不足道。

这种迭代器的设计,及其 .done 和 .value 属性,是与其他语言中的迭代器的工作原理是完全不同的。在 Java 语言中,迭代器有 .hasNext( ) 和 .next( ) 方法。在 Python 语言中, 他们只有一个 single .next( ) 方法以在没有更多值的时候抛出停止迭代 ( StopIteration ) 的异常。 但是这三种设计本质上都返回相同的信息。

一个迭代器对象能够可选择地实现 .return( ) 和 .throw(exc) 方法。for–of 循环能通过调用 .return() 方法来处理过早退出循环的情况。这种过早退出的情况可能是由于出现异常,中断或者 return 语句。如果迭代器需要做一些清理工作或者是释放出其正在使用的一部分资源,其能够通过实现 .return( ) 以达到这一目的。绝大多数的迭代器对象不需要实现这一方法。.throw(exc) 可能更是一个特例: for–of 基本不需要调用这个方法。但是我们下周将会学习更多关于这个方法的内容。

现在,我们已经知道了所有的细节,我们可以采取一个简单的 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 发行版本都支持 for-of 循环。 要使得其被 Chrome 支持,你需要使用 chrome://flags 并且激活“实验性的 JavaScript”。其在微软的浏览器斯巴达也可以运行,但不能在 IE 浏览器的 shipping 版本中运行。如果您想在网络上使用这种新语法,你需要支持 IE 和 Safari 浏览器,你可以使用一个像通天塔或谷歌的 Traceur 的编译器来将你的 ES6 的代码转换为 Web 友好的 ES5 的代码。

在服务器上,你并不需要一个编译器,你今天就可以在 io.js ( 或者 Node 以 --harmony 选项启动 ) 上开始使用 for-of。

( 更新:以前被忽视但仍需要一提的是,for-of 在默认情况下是被 Chrome 浏览器禁用的。 )

{ 结束 : 真的 }

好了,本章结束了,但是我们仍然不能完全掌握 for-of 循环。

在 ES6 中,有新一类的对象能够与 for-of 完美地配合使用。我觉得这个新功能是 ES6 中最神奇的事情。如果你还没有在 Python 和 C#语言中遇到,你可能最初觉得它是多么令人难以置信。但它是写迭代器的最简单的方法,它在重构时是很有用的,它可能改变了我们无论在浏览器还是在服务器上编写异步代码的方式。因此,让我们看看 ES6 生成器并进行深入探讨。

托管地址:这里

PDF 下载

更多参考材料:前端开发规范   ES 6 入门

转载于:https://my.oschina.net/wenquan0hf/blog/496165

深入解析 ES6 系列(二)相关推荐

  1. 重磅:为ES6系列设计的2套习题+答案解析

    ES6系列共20期的连载已经完满结束,但是我们对ES6的学习还不能停止. 学习ES6的重要性不言而喻,毕竟是JavaScript开发的趋势,所有开发者和运行平台都要向ES6规范靠拢.ES6知识已经成为 ...

  2. Tomcat源码解析系列二:Tomcat总体架构

    Tomcat即是一个HTTP服务器,也是一个servlet容器,主要目的就是包装servlet,并对请求响应相应的servlet,纯servlet的web应用似乎很好理解Tomcat是如何装载serv ...

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

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

  4. ES6 系列之模块加载方案

    前言 本篇我们重点介绍以下四种模块加载规范: AMD CMD CommonJS ES6 模块 最后再延伸讲下 Babel 的编译和 webpack 的打包原理. require.js 在了解 AMD ...

  5. ES6 系列之 let 和 const

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

  6. Sublime插件支持Sass编译和Babel解析ES6 .sublime-build文件初探

    用Sublime Text蛮久了,配置配来配去的,每次换电脑都得重头再配过,奈何人老了脑子不中用了,得好好整理一些,下次换电脑就有得参考了.. 同事说,他的WebStorm简直太方便,自身集成了很多方 ...

  7. Android解析WindowManagerService(二)WMS的重要成员和Window的添加过程

    前言 在本系列的上一篇文章中,我们学习了WMS的诞生,WMS被创建后,它的重要的成员有哪些?Window添加过程的WMS部分做了什么呢?这篇文章会给你解答. 1.WMS的重要成员 所谓WMS的重要成员 ...

  8. Remoting系列(二)----建立第一个入门程序

    http://www.cnblogs.com/Ring1981/archive/2006/07/23/455043.aspx Remoting系列(二)----建立第一个入门程序 下面的Remotin ...

  9. 微服务架构系列二:密码强度评测的实现与实验

    本文是继<微服务架构系列一:关键技术与原理研究>的后续,系列一中论述了微服务研究的背景和意义,主要调研了传统架构的发展以及存在的问题和微服务架构的由来,然后针对微服务架构的设计原则.容器技 ...

  10. 【JAVA编码】 JAVA字符编码系列二:Unicode,ISO-8859,GBK,UTF-8编码及相互转换

    http://blog.csdn.net/qinysong/article/details/1179489 这两天抽时间又总结/整理了一下各种编码的实际编码方式,和在Java应用中的使用情况,在这里记 ...

最新文章

  1. 服务器空闲搭建什么网站,空闲的云服务器可以干什么
  2. OSPF的LSA类型 ——连载一路由器LSA
  3. 什么是Ruby on Rails
  4. fail2ban安全设置
  5. 【NGN学习笔记】6 代理(Proxy)和背靠背用户代理(B2BUA)
  6. 同步中心服务器,同步中心以非常慢的速度同步脱机文件 - Windows Server | Microsoft Docs...
  7. 怎么查看页面跳转过程_faststone注册码怎么获取?英文官网打不开
  8. Arrays数组的常用方法
  9. Android反射set/get系统属性(SystemProperties)
  10. linux 打包 压缩
  11. oracle压缩子分压,混合列压缩(HCC)在OLAP及OLTP场景中的测试
  12. Excel导入SQL datetime的处理
  13. 有道词典android wear,iOS版有道词典6.0发布!最好的全能翻译工具
  14. 高级终端termux下载不了Python_最新Termux安装MSF(metasploit)教程
  15. VOIP技术与应用学习分享
  16. 基于AD9854信号发生电路和MSK调制信号
  17. 【欢迎来怼】 Beta发布事后诸葛亮会议
  18. #Reading Paper#Improving Graph Collaborative Filtering with Neighborhood-enriched Contrastive Learni
  19. 黑客因网文作者写太烂盗其账号,帮改文更新修防火墙,网友:大佬能看看我的论文吗?...
  20. 马斯克推荐加密通讯聊天软件Signalv5.13.8跨平台国际版几何管家出品

热门文章

  1. Android开发工程师,前行路上的14项技能
  2. ctrl+d与ctrl+c
  3. Android Studio connot resolve symbol XXX 无法解析的符号
  4. 1.1 项目过程中遇到date类型插入数据库的问题及解决方法
  5. Brute Force(暴力算法)
  6. 边学边写,琐碎记载oracle
  7. ASP.NET 如何在网页中获取根目录
  8. tidyverse —— forcats包
  9. mac下chrome浏览器设置ajax跨域调试
  10. 是时候拥有一个你自己的命令行工具了