ES6(五)迭代器
本文最后更新于:8 个月前
本文介绍了ES6迭代器模式的概念,Iterator接口的遍历过程,如果通过部署默认Iterator接口让对象变成可遍历的,以及Iterator与for…of循环的关系
ES6(五)迭代器
一、迭代器
迭代器模式包含了两个概念:Iterable可迭代对象、Iterator迭代器。前者表示支持迭代操作的数据结构,后者是对于迭代过程的实现。
1、迭代器模式
迭代器模式:通过原生语言结构,让用户无需知道如何迭代就能实现迭代操作。
迭代器模式(特别是在ECMAScript这个语境下)描述了一个方案,即可以把有些结构称为“可迭代对象”(Iterable),因为它们实现了正式的Iterable接口,而且可以通过迭代器Iterator消费。
每个迭代器都会关联一个可迭代对象,而迭代器会暴露迭代其关联可迭代对象的API。迭代器无须了解与其关联的可迭代对象的结构,只需要知道如何取得连续的值。这种概念上的分离正是Iterable和Iterator的强大之处
2、Iterable 可迭代协议
实现Iterable接口(可迭代协议)要求同时具备两种能力:
- 支持迭代的自我识别能力;
- 创建实现Iterator接口的对象的能力。
在ECMAScript中,这意味着必须暴露一个属性作为“默认迭代器”,而且这个属性必须使用特殊的Symbol.iterator作为键。这个默认属性会引用一个迭代器工厂函数,在需要的时候后台会调用这个工厂函数返回一个新的迭代器iterator
检查一个对象是否满足可迭代协议,可以通过查看默认迭代器属性Symbol.iterator
1 |
|
3、Iterator 迭代器协议
Iterator迭代器是一种一次性使用的对象,用于迭代与其关联的可迭代对象。不同迭代器的实例之间没有关联。
迭代器API使用next()
方法遍历数据,next()
方法每次返回一个IteratorResult
对象,包含两个属性done和value。done是boolean
类型,表示后面是否还有值;value表示返回的值。当遍历完毕后继续调用next()
,会一直返回{done:false,value:undefined}
二、Iterator
1. 简介
任何数据结构只要部署 Iterator 接口,就可以完成遍历操作。Iterator 接口主要供for...of
消费。
Iterator 的遍历过程是这样的:
(1)创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
(2)第一次调用指针对象的next
方法,可以将指针指向数据结构的第一个成员。
(3)第二次调用指针对象的next
方法,指针就指向数据结构的第二个成员。
(4)不断调用指针对象的next
方法,直到它指向数据结构的结束位置。
下面模拟实现一个Iterator接口:
1 |
|
2. 默认接口
ES6 规定,默认的 Iterator 接口部署在数据结构的Symbol.iterator
属性,或者说,一个数据结构只要具有Symbol.iterator
属性,就可以认为是“可遍历的”(iterable),就可以被for..of
循环遍历。调用这个接口,就会返回一个编辑器对象。
原生部署了Iterator接口的数据结构有7种:
- Array
- Set
- Map
- String
- 函数的arguments对象
- NodeList对象
- TypedArray
对象Object默认没有Iterator接口。
1 |
|
一个对象要想能够执行 for..of 循环,就必须在 Symbol.iterator 属性上部署遍历器生成方法(原型链上部署也可以)
1 |
|
1 |
|
Symbol.iterator()
方法的最简单实现,还是使用 Generator 函数
1 |
|
3. 调用Iterator接口的场合
以下场合都会调用默认的Symbol.iterator接口
- 解构赋值,数组和Set的解构赋值
- 扩展运算符
yield*
,后面跟的是一个可遍历的结构,它会调用该结构的遍历器接口。
三、for…of 循环
一个数据结构只要部署了Symbol.iterator
属性,就被视为具有 iterator 接口,就可以用for...of
循环遍历它的成员。也就是说,for...of
循环内部调用的是数据结构的Symbol.iterator
方法。
可以使用for...of
循环遍历的数据结构:数组、Set 和 Map 结构、某些类似数组的对象(比如arguments
对象、DOM NodeList 对象)、 Generator 对象,以及字符串。
for…in 循环主要为遍历对象设计,不适合遍历数组。它有以下缺点:
- 数组的键名是数字,但是
for...in
循环是以字符串作为键名“0”、“1”、“2”等等。 for...in
循环不仅遍历数字键名,还会遍历手动添加的其他键,甚至包括原型链上的键。- 某些情况下,
for...in
循环会以任意顺序遍历键名。
for…of 循环与 for…in 循环相比,它有着同for...in
一样的简洁语法,但是没有for...in
那些缺点
for…of 循环与 数组的 forEach 相方法比,它可以与break
、continue
和return
配合使用,但是后者不行。