文章目录

  • 简介
  • 什么是iteration
  • Iterable对象
  • 普通对象不是可遍历的
  • 自定义iterables
  • 关闭iterators
  • 总结

简介

为了方便集合数据的遍历,在ES6中引入了一个iteration的概念。为我们提供了更加方便的数据遍历的手段。

一起来学习一下吧。

什么是iteration

iteration也称为遍历,就是像数据库的游标一样,一步一步的遍历集合或者对象的数据。

根据ES6的定义,iteration主要由三部分组成:

  1. Iterable

先看下Iterable的定义:

interface Iterable {[Symbol.iterator]() : Iterator;
}

Iterable表示这个对象里面有可遍历的数据,并且需要实现一个可以生成Iterator的工厂方法。

  1. Iterator
interface Iterator {next() : IteratorResult;
}

可以从Iterable中构建Iterator。Iterator是一个类似游标的概念,可以通过next访问到IteratorResult。

  1. IteratorResult

IteratorResult是每次调用next方法得到的数据。

interface IteratorResult {value: any;done: boolean;
}

IteratorResult中除了有一个value值表示要获取到的数据之外,还有一个done,表示是否遍历完成。

Iterable是一个接口,通过这个接口,我们可以连接数据提供者和数据消费者。

Iterable对象叫做数据提供者。对于数据消费者来说,除了可以调用next方法来获取数据之外,还可以使用for-of 或者 …扩展运算符来进行遍历。

for-of的例子:

  for (const x of ['a', 'b', 'c']) {console.log(x);}

…扩展运算符的例子:

 const arr = [...new Set(['a', 'b', 'c'])];

Iterable对象

ES6中,可以被称为Iterable对象的有下面几种:

  • Arrays
  • Strings
  • Maps
  • Sets
  • DOM

先看一个Arrays的情况,假如我们有一个Arrays,可以通过Symbol.iterator这个key来获取到Iterator:


> const arr = ['a', 'b', 'c'];
> const iter = arr[Symbol.iterator]();
> iter.next()
{ value: 'a', done: false }
> iter.next()
{ value: 'b', done: false }
> iter.next()
{ value: 'c', done: false }
> iter.next()
{ value: undefined, done: true }

更加简单的办法就是使用for-of:

for (const x of ['a', 'b']) {console.log(x);
}
// Output:
// 'a'
// 'b'

看一个遍历String的情况,String的遍历是通过Unicode code points来区分的:

for (const x of 'a\uD83D\uDC0A') {console.log(x);
}
// Output:
// 'a'
// '\uD83D\uDC0A' (crocodile emoji)

上面的例子中,基础类型的String在遍历的时候,会自动转换成为String对象。

Maps是通过遍历entries来实现的:

const map = new Map().set('a', 1).set('b', 2);
for (const pair of map) {console.log(pair);
}
// Output:
// ['a', 1]
// ['b', 2]

还记得之前提到的WeakMaps吗?

WeakMap,WeakSet和Map于Set的区别在于,WeakMap的key只能是Object对象,不能是基本类型。

为什么会有WeakMap呢?

对于JS中的Map来说,通常需要维护两个数组,第一个数组中存储key,第二个数组中存储value。每次添加和删除item的时候,都需要同时操作两个数组。

这种实现有两个缺点,第一个缺点是每次查找的时候都需要遍历key的数组,然后找到对应的index,再通过index来从第二个数组中查找value。

第二个缺点就是key和value是强绑定的,即使key不再被使用了,也不会被垃圾回收。

所以引入了WeakMap的概念,在WeakMap中,key和value没有这样的强绑定关系,key如果不再被使用的话,可以被垃圾回收器回收。

因为引用关系是weak的,所以weakMap不支持key的遍历,如果你想遍历key的话,请使用Map。

看下Set的遍历:

const set = new Set().add('a').add('b');
for (const x of set) {console.log(x);
}
// Output:
// 'a'
// 'b'

我们还可以遍历arguments对象:

function printArgs() {for (const x of arguments) {console.log(x);}
}
printArgs('a', 'b');// Output:
// 'a'
// 'b'

对于大部分DOM来说,也是可以遍历的:

for (const node of document.querySelectorAll('div')) {···
}

普通对象不是可遍历的

简单对象就是通过字面量创建出来的对象,这些对象虽然也有key-value的内容,但是是不可遍历的。

为什么呢?

因为可遍历对象比如Array,Map,Set也是普通对象的一种特例。如果普通对象可以遍历了,那么会导致可以遍历对象的一些遍历中的冲突。

for (const x of {}) { // TypeErrorconsole.log(x);
}

虽然不能直接遍历普通对象,但是我们可以通过使用objectEntries方法来遍历普通对象。

先看下objectEntries的实现:

function objectEntries(obj) {let iter = Reflect.ownKeys(obj)[Symbol.iterator]();return {[Symbol.iterator]() {return this;},next() {let { done, value: key } = iter.next();if (done) {return { done: true };}return { value: [key, obj[key]] };}};
}

我们通过Reflect.ownKeys()反射拿到对象中的iterator.然后通过这个iterator来进行普通对象的遍历。

看下具体的使用:


const obj = { first: 'Jane', last: 'Doe' };for (const [key,value] of objectEntries(obj)) {console.log(`${key}: ${value}`);
}// Output:
// first: Jane
// last: Doe

自定义iterables

除了ES6中默认的iterables之外,我们还可以自定义iterables。

因为iterables是一个接口,我们只需要实现它就可以了。我们看一个iterables的例子:

function iterateOver(...args) {let index = 0;const iterable = {[Symbol.iterator]() {const iterator = {next() {if (index < args.length) {return { value: args[index++] };} else {return { done: true };}}};return iterator;}}return iterable;
}

iterateOver方法会返回一个iterable对象。在这个对象中,我们实现了Symbol.iterator为key的方法。这个方法返回一个iterator,在iterator中,我们实现了next方法。

上面的方法使用起来是下面的效果:

// Using `iterateOver()`:
for (const x of iterateOver('fee', 'fi', 'fo', 'fum')) {console.log(x);
}// Output:
// fee
// fi
// fo
// fum

上面的例子中,如果Symbol.iterator返回的对象是iterable本身,那么iterable也是一个iterator。

function iterateOver(...args) {let index = 0;const iterable = {[Symbol.iterator]() {return this;},next() {if (index < args.length) {return { value: args[index++] };} else {return { done: true };}},};return iterable;
}

这样做的好处就是,我们可以使用for-of同时遍历iterables和iterators,如下所示:

const arr = ['a', 'b'];
const iterator = arr[Symbol.iterator]();for (const x of iterator) {console.log(x); // abreak;
}// Continue with same iterator:
for (const x of iterator) {console.log(x); // b
}

关闭iterators

如果我们需要遍历的过程中,从iterators中返回该怎么处理呢?

通过实现return方法,我们可以在程序中断的时候(break,return,throw)调用iterators的return。

function createIterable() {let done = false;const iterable = {[Symbol.iterator]() {return this;},next() {if (!done) {done = true;return { done: false, value: 'a' };} else {return { done: true, value: undefined };}},return() {console.log('return() was called!');},};return iterable;
}
for (const x of createIterable()) {console.log(x);break;
}
// Output:
// a
// return() was called!

上面例子中,我们通过break来中断遍历,最终导致return方法的调用。

注意,return方法必须要返回一个对象,{ done: true, value: x }

总结

上面就是ES6中引入的Iterables和iterators的一些概念。

本文作者:flydean程序那些事

本文链接:http://www.flydean.com/es6-iterables-iterator/

本文来源:flydean的博客

欢迎关注我的公众号:「程序那些事」最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

ES6中的新特性:Iterables和iterators相关推荐

  1. 前端面试题二:ES6/7/8新特性、性能优化、数据交互、H5新特性

    目录 一.ES6/7/8新特性 二.性能优化 三.数据交互 四.H5新特性 一.ES6/7/8新特性 1.ES6中新增了哪些数据类型? Symbol类型(基本) Set类型(复杂) Map类型(复杂) ...

  2. php v5.,PHP V5.3 中的新特性,第 5 部分- 从 PHP V5.2 升级到 PHP V5.3

    PHP V5.3 中的新特性,第 5 部分: 从PHP V5.2 升级到 PHP V5.3 1 2 3 4 5 下一页 PHP V5.3 将于不久后发布."PHP V5.3 中的新特性&qu ...

  3. Entity Framework 4.3 中的新特性

    原文地址:http://www.cnblogs.com/supercpp/archive/2012/02/20/2354751.html EF4.3于2月9号正式发布了,微软的EF小组最近一年开始发力 ...

  4. Spring 2.5:Spring MVC中的新特性

    转载说明:infoQ就是牛人多,看人家去年就把Spring2.5注视驱动的MVC写出来了,还是这么详细,我真是自叹不如,今天偶尔看到这篇文章非常认真的拜读了2遍,简直是茅厕顿开啊....\(^o^)/ ...

  5. iOS7 中的新特性

    iOS7 中的新特性 太阳火神的美丽人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:太阳 ...

  6. JDK 8 中的新特性

    目录 JDK 8 中的新特性 JDK 8 中的新特性 JDK 版本说明 JDK 8 版本说明 Java Platform, Standard Edition 8 是一个拥有丰富特性的主要版本.本文档总 ...

  7. iOS 各版本中的新特性(What's New in iOS)- 目录翻译完成

    iOS 各版本中的新特性(What's New in iOS) 太阳火神的美丽人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一致&q ...

  8. ES6简介、新特性、Babel编译器、babel-cli工具、babel-polyfill工具(安装和使用)

    目录 简介 ECMAScript 的历史 ES6新特性 1.语法方面 2.功能方面 ​ Babel编译器 babel-cli工具 第一步:创建一个文件夹,名称为app,在vscode中打开终端,终端路 ...

  9. 最全的—— ES6有哪些新特性?

    目录 ES6新特性 1.let和const 2.symbol 3.模板字符串 3.1 字符串新方法(补充) 4.解构表达式 4.1 数组解构 4.2 对象解构 5.对象方面 5.1 Map和Set 5 ...

最新文章

  1. XML 与DataSet 对象的关系
  2. Eclipse快捷键:最常用且高效的快捷键
  3. 数组翻转_算法系列之翻转单词顺序
  4. python 知识 rstrip,strip,lstrip
  5. GARFIELD@04-30-2005
  6. 为什么在生产中进行调试是如此诱人?
  7. RCNN,fast R-CNN,faster R-CNN
  8. 关闭防火墙linux 16.04,如何在Ubuntu 16.04上配置和设置防火墙
  9. 学号20155308 2016-2017-2 《Java程序设计》实验一(Java开发环境的熟悉)实验报告...
  10. 9.6 awk(上);9.7 awk(下)
  11. SpringBoot项目:抽奖精灵
  12. ILSVRC2012数据集介绍
  13. java输战舰_什么是最好的战舰AI?
  14. PTA(Java类与对象 方法,方法重载) 7-1 设计一个风扇Fan类
  15. 工业机器人演示码垛和卸垛_机器人在码垛卸垛行业的应用
  16. php cmyk图片,php – 使用Imagick将图像从RGB转换为CMYK
  17. 移动通讯技术的发展历史
  18. 萤光云服务器,你值得拥有
  19. 格网DEM生成不规则三角网TIN
  20. php ssl tls_SSL/TLS多种证书类型的转换

热门文章

  1. VMware多虚拟机网络配置
  2. 机器学习进阶-优化的近邻算法
  3. django添加mysql数据库_Django添加mysql数据库关联时出现的错误
  4. elasticsearch java对象 驼峰原则_Elasticsearch简介与实战
  5. Treap原理和实现方法
  6. 特殊方法求1~n的和
  7. 20.IDA-修改二进制文件、显示修改点
  8. OpenCV_006-OpenCV 轨迹栏作为调色板
  9. 用FlatBuffers提升Android平台上Facebook的性能
  10. 第27讲:令人抓狂的 JavaScript 混淆技术