引入
系统学习ES6各种特性,了解背后的原理。
本章记录Iterator
迭代器(遍历器)
笔记
1.1 迭代器的含义
迭代器是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构,只要部署Iterator
接口,就可以完成遍历操作。
其作用有三点:
- 为各种数据结构提供一个统一的、简便的访问接口
- 使得数据结构的成员能够按某种次序排列
- 供ES6中的for of循环使用
Iterator
遍历过程如下:
- 创建一个指针对象,指向当前数据结构的起始位置。
- 第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员
- 再次调用next方法,指向第二个成员
- 不断调用next方法,直到它指向数据结构的结束位置。
每次调用next方法都会返回当前指向的成员信息,即{value, done}
其中done表示是否遍历结束(指向了结束位置)
1.2 默认Iterator接口
数据结构只要部署了Iterator
接口,就称为可迭代(可遍历)的。
ES6规定,默认的Iterator
接口部署在此数据结构的Symbol.iterator
值为名称的属性上。
所以只要某个数据结构有该属性,就可以认为是可遍历的。调用该方法就可以得到当前数据结构默认的遍历器生成函数
let t = [6, 4, 2]
let it = t[Symbol.iterator]() //遍历器对象
// 自定义可迭代对象
let obj = {
[Symbol.iterator](){
return {
next(){
return {
value:1,
done:true
}
}
}
}
}
Map
, Array
, Set
, String
, TypedArray
等等都原生具备了Iterator
接口,可以直接用for of
进行遍历。
不过注意Map
迭代时返回的是键值对数组,而Set
是一个值
而Object
并没有部署该接口(因为对象的属性是无序的,所以严格上说其部署该接口没有必要)
但是如果一定要遍历的话,可以使用Object.values()
等方法生成可迭代对象来使用for of
对于类似数组的对象(存在数值键名和length属性),部署Iterator
接口可以引用数组的Symbol.iterator
接口。
如:NodeList
上的接口就是如此实现的
NodeList.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator]
1.3 调用Iterator接口的场合
- 解构赋值
- 扩展运算符(...)
- yield* (如
yield* [1,2,3]
) - 其他场合:
for of
,Array.from()
,Map()
,Set()
,Promise.all()
,Promise.race()
1.4 Iterator接口与Generator函数
迭代器接口的最简单实现还是使用Generator
函数
let obj = {
*[Symbol.iterator](){
yield 'hello';
yield 'world';
}
}
[...obj] // ['hello', 'world']
1.5 遍历器对象的return(), throw()
遍历器对象除了具有next方法,还可以具有可选的return、throw方法
return
方法必须返回一个对象,这是Generator规格决定的。
return
方法的使用场景:
当for of
循环提前退出(因为报错或break、continue),就会调用return方法
也可以调用迭代器对象的return()
方法,将迭代器将保持在“完成”状态
throw方法主要用于Gererator函数,此处不展开介绍。