阅读更多

0顶
0踩

Web前端
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
  • 大小: 20.8 KB
0
0
评论 共 2 条 请登录后发表评论
2 楼 dsjt 2015-06-17 16:54
ECMAScript 4 是这样区分的
for each in遍历值
for in 遍历属性。
1 楼 yixiandave 2015-06-17 16:26

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

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

    【探秘ES6】系列专栏 , 供大家学习借鉴。本文为该系列的第二篇。   你是如何遍历数组中的元素的?20年前JavaScript刚进入视野时,你应该是这样写的: for (var index = 0; index &lt; myArray.length; ...

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

    【探秘ES6】系列专栏【探秘ES6】系列专栏(一):ES6简介【探秘ES6】系列专栏(二):迭代器和for-of循环【探秘ES6】系列专栏(三):生成器【探秘ES6】系列专栏(四):模版字符串【探秘ES6】系列专栏(五):剩余参数和默认...

  • 【探秘ES6】系列专栏

    【探秘ES6】系列专栏(二):迭代器和for-of循环 【探秘ES6】系列专栏(三):生成器 【探秘ES6】系列专栏(四):模版字符串 【探秘ES6】系列专栏(五):剩余参数和默认参数 【探秘ES6】系列专栏(六):...

  • ES6 Iterator 和 for...of 循环

    for...of 循环1.for...of(1).基本使用const arr = ['red', 'green', 'blue']; for(let v of arr) { console.log(v); // red green blue } (2).注意这几点:A.这是目前遍历数组最简洁和直接的语法;B.它避免了...

  • 【探秘ES6】系列专栏(三):生成器

    【探秘ES6】系列专栏 , 供大家学习借鉴。本文为该系列的第三篇。 ES6生成器介绍 什么是生成器呢? 请先看看以下代码。 function* quips(name) {   yield "hello " + name + "!";   yield ...

  • 【探秘ES6】系列专栏(六):解构赋值

    【探秘ES6】系列专栏(六):解构赋值 发表于2015-07-07 10:55|11405次阅读| 来源Mozilla Web开发者博客|2 条评论| 作者Jason Orendorff 探秘ES6ES6Web开发JavaScript 摘要:新一代JavaScript标准ES6正式发布。...

  • 探秘ES6系列专栏,带你全面了解ES6新特性

    专栏(二):迭代器和for-of循环 专栏(三):生成器 专栏(四):模版字符串 专栏(五):剩余参数和默认参数 专栏(六):解构赋值 专栏(七):箭头函数 专栏(八):JS的第七种基本类型Symbols...

  • 【探秘ES6】系列专栏(一):ES6简介

    下篇,我们将会介绍ES6的iterators(迭代器)和新的循环语句for-of。(译者:李全锋 责编:陈秋歌) 原文链接: ES6 In Depth: An Introduction 本译文遵循Creative Commons Attribution Share-Alike License ...

  • 【探秘ES6】系列专栏(四):模版字符串

    【探秘ES6】系列专栏 , 供大家学习借鉴。本文为该系列的第四篇。 前两次学习了 生成器 和 迭代器 以后,脑袋有没有一团浆糊?哈哈。我承诺过本次我们将学习一些简单的东西。 那我们现在就开始吧! “小...

  • 【探秘ES6】系列专栏(八):JS的第七种基本类型Symbols

    【探秘ES6】系列专栏 ,供大家学习借鉴。本文为该系列的第八篇。   本期我们要讨论的symbols是个什么东西呢? 这里的Symbols不是指的徽标。 也不是能在代码中使用的小图片。 它也不是代表其它任何...

  • ES6 的 for..of 和 Generator,从伪数组 jQuery 对象说起

    【探秘ES6】系列专栏(八):JS的第七种基本类型Symbols 和 Symbol - JavaScript | MDN 实现 知道了规矩,实现起来就好办了 jQuery.fn[Symbol.iterator] = function() { return (function(_this) { var ...

  • ES6学习——生成器(Generators):概念介绍

    简单解释生成器就是一种能中断和恢复自己的函数,具体的解释可以参考【探秘ES6】系列专栏(三):生成器,这篇文章解释的比较详细,下面有些内容我就直接使用这篇文章的了。 生成器的两点特征: 生成器函数以...

  • ES6:解构赋值

    转载自:http://www.csdn.net/article/2015-07-07/2825149-es6-in-depth-destructuring ...为了让大家对ES6的诸多新特性有更深入的了解,Mozilla Web开发者博客推出了《ES6 In Depth》系列文章。CSDN已获授权,将持

  • 关于for...in和for...of的思考

    关于for...in和for...of的思考 在编写js代码的时候,我们经常性的要对数据集合进行遍历,Array、Object、以及ES6新属性Map、Set,甚至String类型都是可遍历的。 我们来看看,一般我们都用什么方法去遍历这些集合: 以...

  • ES6学习路线图

    【探秘ES6】系列专栏(二):迭代器和for-of循环 http://my.oschina.net/1pei/blog/520584 【翻译】Iterables and iterators in ECMAScript 6 http://my.oschina.net/1pei/blog/596510 ECMAScript 6 Promises...

  • 最近遇到的前端面试题(2017.03.01更新版)

    以下问题解释非本人原创,是整理后觉得更容易理解的版本,...应用层(HTTP、SMTP、FTP、POP3)运输层(TCP、UDP)网络层(IP(路由器))数据链路层(网桥(CSMA/CD、PPP))物理层(集线器) 1. 查找域名对应IP地址 这一步包

  • 转载的一些面试题

    一. 输入url后的加载过程 从输入 URL 到页面加载完成的过程中都发生了什么 ...物理层(集线器) 1. 查找域名对应IP地址 这一步包括 DNS 具体的查找过程,包括:浏览器缓存-&gt;系统缓存-&gt;...

  • Python项目-自动办公-56 Word_docx_格式套用.zip

    Python课程设计,含有代码注释,新手也可看懂。毕业设计、期末大作业、课程设计、高分必看,下载下来,简单部署,就可以使用。 包含:项目源码、数据库脚本、软件工具等,该项目可以作为毕设、课程设计使用,前后端代码都在里面。 该系统功能完善、界面美观、操作简单、功能齐全、管理便捷,具有很高的实际应用价值。

  • 《松鼠》生态性课堂体验教案.docx

    《松鼠》生态性课堂体验教案

  • Java系统源码+智慧图书管理系统

    Java系统源码+智慧图书管理系统 内容概要: 本资源包含了完整的Java前后端源码及说明文档,适用于想要快速搭建并部署Java Web应用程序的开发者、学习者。 技术栈: 后端:Java生态系统,包含Spring Boot、Shiro、MyBatis等,数据库使用Mysql 前端:Vue、Bootstrap、Jquery等 适用场景示例: 1、毕业生希望快速启动一个新的Java Web应用程序。 2、团队寻找一个稳定的模板来加速产品开发周期。 3、教育机构或个人学习者用于教学目的或自学练习。 4、创业公司需要一个可以立即投入使用的MVP(最小可行产品)。

Global site tag (gtag.js) - Google Analytics