迭代:按照顺序反复多次执行一段程序,通常会有明确的终止条件。
ES6加入的特性,用来为不同结构的数据提供统一的迭代访问方式
- 是迭代器模式的实现
迭代器模式
实现了 Interable 接口的数据结构称为“可迭代对象”,都可以通过实现了 Interator 的结构(迭代器)消费。
接口区别
- Interable:用于在需要时获取一个全新的 Intertor(迭代器)
- Intertor:用于迭代关联的数据,含有迭代方法,和独属于该迭代器的当前迭代位置
迭代器是按需创建的一次性对象,与一个可迭代对象关联,迭代器会暴露迭代该对象的API。迭代器无需了解可迭代对象的结构,只要知道如何连续的取得其中的值。
可迭代协议(Iterable)
obj[Symbol.iterator] = function () {return iterator}class MyObj {[Symbol.iterator] () {return iterator}}
- 必须使用
Symbol.iterator作为属性的key,且值为一个迭代器工厂函数,该函数返回一个迭代器- 因此只要有
Symbol.iterator属性,那么就是可迭代的,这个key是强制规定的
- 因此只要有
- 如 for…of 等在迭代时,会自动调用该key,获取迭代器进行迭代
默认部署了Iterable的类型
- Array
- Map
- Set
- String
- TypedArray
- 函数的 arguments 对象
- NodeList 对象
接收可迭代对象的原生特性
- for-of 循环
- 数组解构
- 扩展操作符
- Array.from()
- 创建集合(Set)
- 创建映射(Map)
- Promise.all 的参数
- Promise.race 的参数
- yield*操作符,在生成器中使用
这些特性,都会自动调用可迭代对象的迭代器工厂函数,创建迭代器后进行迭代
迭代器协议(Itertor)
实现 Itertor 接口的协议规则,也是其内部运行的原理。Intertor是一种一次性的对象,用于迭代与其关联的可迭代对象。
迭代规则
- Iterator 对象必须有 next 方法,使用 next 方法对关联对象进行迭代。
- 每一次调用next方法,都会指向关联对象的下一个成员,直到指向了最后一个
- 每次调用next方法都需要返回一个 InteratorResult 对象,包含两个属性
- value:当前指向的成员的值
- done:布尔值,当前遍历器是否已经遍历完成
- 如果next返回一个非对象,就会抛出错误
自定义迭代器
// Counter 的实例应该迭代 limit 次// 这个类实现了可迭代接口(Iterable),接口的值是一个迭代器工厂函数// 调用该工厂函数会返回,一个实现了迭代器接口(Iterator)的迭代器对象class Counter {constructor(limit) {this.limit = limit;}[Symbol.iterator] () {let count = 1let limit = this.limitreturn {next() {if (count <= limit) {return { done: false, value: count++ }} else {return { done: true }}}}}}let counter = new Counter(3)const it = f[Symbol.iterator]() // 通过 Iterable 接口实现获取 Itertor 实现it.next() // { value: 0, done: false }it.next() // { value: 1, done: false }it.next() // { value: undefined, done: true }for (let i of counter) { console.log(i) }// 1// 2// 3
提前终止迭代
Iterator 对象有可选 return 的方法,用于提前终止迭代
- 该方法用于主动的提前关闭迭代,也是返回一个 InteratorResult 对象,可以只有 done
当然也需要执行一定的逻辑,放止next的在调用
class Counter {constructor(limit) {this.limit = limit}[Symbol.iterator]() {let count = 1let limit = this.limitreturn {next() {if (count <= limit) {return { done: false, value: count++ }} else {return { done: true }}},return() {count = limit + 1return { done: true }}}}}
for…of 循环可以通过break、continue、return、break或throw前置退出
