迭代:按照顺序反复多次执行一段程序,通常会有明确的终止条件。

ES6加入的特性,用来为不同结构的数据提供统一的迭代访问方式

  • 迭代器模式的实现

迭代器模式

实现了 Interable 接口的数据结构称为“可迭代对象”,都可以通过实现了 Interator 的结构(迭代器)消费。

接口区别

  • Interable:用于在需要时获取一个全新的 Intertor(迭代器)
  • Intertor:用于迭代关联的数据,含有迭代方法,和独属于该迭代器的当前迭代位置

迭代器是按需创建的一次性对象,与一个可迭代对象关联,迭代器会暴露迭代该对象的API。迭代器无需了解可迭代对象的结构,只要知道如何连续的取得其中的值。

可迭代协议(Iterable)

  1. obj[Symbol.iterator] = function () {
  2. return iterator
  3. }
  4. class MyObj {
  5. [Symbol.iterator] () {
  6. return iterator
  7. }
  8. }
  • 必须使用 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是一种一次性的对象,用于迭代与其关联的可迭代对象。

迭代规则

  1. Iterator 对象必须有 next 方法,使用 next 方法对关联对象进行迭代。
    • 每一次调用next方法,都会指向关联对象的下一个成员,直到指向了最后一个
  2. 每次调用next方法都需要返回一个 InteratorResult 对象,包含两个属性
    • value:当前指向的成员的值
    • done:布尔值,当前遍历器是否已经遍历完成
  3. 如果next返回一个非对象,就会抛出错误

自定义迭代器

  1. // Counter 的实例应该迭代 limit 次
  2. // 这个类实现了可迭代接口(Iterable),接口的值是一个迭代器工厂函数
  3. // 调用该工厂函数会返回,一个实现了迭代器接口(Iterator)的迭代器对象
  4. class Counter {
  5. constructor(limit) {
  6. this.limit = limit;
  7. }
  8. [Symbol.iterator] () {
  9. let count = 1
  10. let limit = this.limit
  11. return {
  12. next() {
  13. if (count <= limit) {
  14. return { done: false, value: count++ }
  15. } else {
  16. return { done: true }
  17. }
  18. }
  19. }
  20. }
  21. }
  22. let counter = new Counter(3)
  23. const it = f[Symbol.iterator]() // 通过 Iterable 接口实现获取 Itertor 实现
  24. it.next() // { value: 0, done: false }
  25. it.next() // { value: 1, done: false }
  26. it.next() // { value: undefined, done: true }
  27. for (let i of counter) { console.log(i) }
  28. // 1
  29. // 2
  30. // 3

提前终止迭代

Iterator 对象有可选 return 的方法,用于提前终止迭代

  • 该方法用于主动的提前关闭迭代,也是返回一个 InteratorResult 对象,可以只有 done
  • 当然也需要执行一定的逻辑,放止next的在调用

    1. class Counter {
    2. constructor(limit) {
    3. this.limit = limit
    4. }
    5. [Symbol.iterator]() {
    6. let count = 1
    7. let limit = this.limit
    8. return {
    9. next() {
    10. if (count <= limit) {
    11. return { done: false, value: count++ }
    12. } else {
    13. return { done: true }
    14. }
    15. },
    16. return() {
    17. count = limit + 1
    18. return { done: true }
    19. }
    20. }
    21. }
    22. }
  • for…of 循环可以通过break、continue、return、break或throw前置退出