手写系列 - iterator迭代器

157 阅读3分钟

前置知识:迭代协议

迭代协议并不是新的内置实现或语法,而是协议。这些协议可以被任何遵循某些约定的对象来实现。

迭代协议具体分为两个协议:可迭代协议迭代器协议

可迭代协议

可迭代协议允许 JavaScript 对象定义或定制它们的迭代行为,例如,在一个 for..of 结构中,哪些值可以被遍历到。

要成为可迭代对象,该对象必须实现 @@iterator 方法,这意味着对象(或者它原型链上的某个对象)必须有一个键为 @@iterator 的属性,可通过常量 Symbol.iterator 访问该属性。

[Symbol.iterator] 一个无参数的函数,其返回值为一个符合迭代器协议的对象。

当一个对象需要被迭代的时候(比如被置入一个 for...of 循环时),首先,会不带参数调用它的 @@iterator 方法,然后使用此方法返回的迭代器获得要迭代的值。

简单总结一下:可迭代协议定义了如何才能成为一个可迭代对象,就是对象必须实现一个 @@iterator 方法,调用该方法时会返回一个迭代器。

迭代器协议

迭代器协议定义了产生一系列值(无论是有限个还是无限个)的标准方式,当值为有限个时,所有的值都被迭代完毕后,则会返回一个默认返回值。

只有实现了一个拥有以下语义(semantic)的 next() 方法,一个对象才能成为迭代器:

next() 无参数或者接受一个参数的函数,并返回符合 IteratorResult 接口的对象(见下文)。

所有迭代器协议的方法(next()、return() 和 throw())都应返回实现 IteratorResult 接口的对象。它必须有以下属性:

  • done 如果迭代器能够生成序列中的下一个值,则返回 false 布尔值。(这等价于没有指定 done 这个属性。)如果迭代器已将序列迭代完毕,则为 true。这种情况下,value 是可选的,如果它依然存在,即为迭代结束之后的默认返回值。

  • value 迭代器返回的任何 JavaScript 值。done 为 true 时可省略。

简单总结一下:迭代器协议定义了如何才能成为一个迭代器,就是对象要有一个上面所讲的 next() 方法。并简单体现了迭代器的工作流程。

内置的可迭代对象

String、Array、TypedArray、Map、Set 以及 Intl.Segments (en-US) 都是内置的可迭代对象,因为它们的每个 prototype 对象都实现了 @@iterator 方法。此外,arguments 对象和一些 DOM 集合类型,如 NodeList 也是可迭代的。

让对象类型成为可迭代对象

// 让对象可迭代,设置 Symbol.iterator 属性是一个函数,返回一个迭代器
Object.prototype[Symbol.iterator] = function () {
  const keys = Object.keys(this);

  let index = 0;
  // 返回一个迭代器对象
  return (myIterator = {
    next: () => {
      return {
        done: index >= keys.length,
        value: this[keys[index++]],
      };
    },
  });
};

const obj = { name: "xiaoming", age: 100 };

console.log([...obj]);