Iterator 遍历器


Iterator 遍历器

ES6 中引入了很多此前没有但是却非常重要的概念,Iterator就是其中一个。Iterator对象是一个指针对象,实现类似于单项链表的数据结构,通过next()将指针指向下一个节点 ———— 这里也就是先简单做一个概念性的介绍,后面将通过实例为大家演示。

本节内容概述

  • 简介Symbol数据类型
  • 具有[Symbol.iterator]属性的数据类型
  • 生成Iterator对象
  • Generator返回的也是Iterator对象
  • 接下来...

简介Symbol数据类型

console.log(Array.prototype.slice)  // [Function: slice]
console.log(Array.prototype[Symbol.iterator])  // [Function: values]

数组的slice属性大家都比较熟悉了,就是一个函数,可以通过Array.prototype.slice得到。这里的slice是一个字符串,但是我们获取Array.prototype[Symbol.iterator]可以得到一个函数,只不过这里的[Symbol.iterator]Symbol数据类型,不是字符串。但是没关系,Symbol数据类型也可以作为对象属性的key。如下:

var obj = {}
obj.a = 100
obj[Symbol.iterator] = 200
console.log(obj)  // {a: 100, Symbol(Symbol.iterator): 200}

在此小节中,你只需要知道[Symbol.iterator]是一个特殊的数据类型Symbol类型,但是也可以像number string类型一样,作为对象的属性key来使用

原生具有[Symbol.iterator]属性的数据类型

在 ES6 中,原生具有[Symbol.iterator]属性数据类型有:数组、某些类似数组的对象(如argumentsNodeList)、SetMap。其中,SetMap也是 ES6 中新增的数据类型。

// 数组
console.log([1, 2, 3][Symbol.iterator])  // function values() { [native code] }
// 某些类似数组的对象,NoeList
console.log(document.getElementsByTagName('div')[Symbol.iterator])  // function values() { [native code] }

原生具有[Symbol.iterator]属性数据类型有一个特点,就是可以使用for...of来取值,例如

var item
for (item of [100, 200, 300]) {
    console.log(item)
}
// 打印出:100 200 300
// 注意,这里每次获取的 item 是数组的 value,而不是 index ,这一点和 传统 for 循环以及 for...in 完全不一样

而具有[Symbol.iterator]属性的对象,都可以一键生成一个Iterator对象。如何生成以及生成之后什么样子,还有生成之后的作用,下文分解。

不要着急,也不要跳过本文的任何步骤,一步一步跟着我的节奏来看。

生成Iterator对象

定义一个数组,然后生成数组的Iterator对象

const arr = [100, 200, 300]
const iterator = arr[Symbol.iterator]()  // 通过执行 [Symbol.iterator] 的属性值(函数)来返回一个 iterator 对象

好,现在生成了iterator,那么该如何使用它呢 ———— 有两种方式:nextfor...of

先说第一种,next

console.log(iterator.next())  // { value: 100, done: false }
console.log(iterator.next())  // { value: 200, done: false }
console.log(iterator.next())  // { value: 300, done: false }
console.log(iterator.next())  // { value: undefined, done: true }

看到这里,再结合上一节内容,是不是似曾相识的感觉?(额,没有的话,那你就回去重新看上一节的内容吧) iterator对象可以通过next()方法逐步获取每个元素的值,以{ value: ..., done: ... }形式返回,value就是值,done表示是否到已经获取完成。

再说第二种,for...of

let i
for (i of iterator) {
    console.log(i)
}
// 打印:100 200 300

上面使用for...of遍历iterator对象,可以直接将其值获取出来。这里的“值”就对应着上面next()返回的结果的value属性

Generator返回的也是Iterator对象

看到这里,你大体也应该明白了,上一节演示的Generator,就是生成一个Iterator对象。因此才会有next(),也可以通过for...of来遍历。拿出上一节的例子再做一次演示:

function* Hello() {
    yield 100
    yield (function () {return 200})()
    return 300
}
const h = Hello()
console.log(h[Symbol.iterator])  // [Function: [Symbol.iterator]]

执行const h = Hello()得到的就是一个iterator对象,因为h[Symbol.iterator]是有值的。既然是iterator对象,那么就可以使用next()for...of进行操作

console.log(h.next())  // { value: 100, done: false }
console.log(h.next())  // { value: 200, done: false }
console.log(h.next())  // { value: 300, done: false }
console.log(h.next())  // { value: undefined, done: true }

let i
for (i of h) {
    console.log(i)
}

接下来...

这一节我们花费很大力气,从Iterator又回归到了Generator,目的就是为了看看Generator到底是一个什么东西。了解其本质,才能更好的使用它,否则总有一种抓瞎的感觉。

接下来我们就Generator具体有哪些使用场景。