欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

js 迭代器模式

最编程 2024-08-06 12:52:43
...

迭代器模式(特别是在 ECMAScript 这个语境下)描述了一个方案,即可以把有些结构称为“可迭 代对象”(iterable),因为它们实现了正式的 Iterable 接口,而且可以通过迭代器 Iterator 消费。

可迭代对象是一种抽象的说法。基本上,可以把可迭代对象理解成数组或集合这样的集合类型的对 象。它们包含的元素都是有限的,而且都具有无歧义的遍历顺序:

// 数组的元素是有限的
// 递增索引可以按序访问每个元素 let arr = [3, 1, 4];
// 集合的元素是有限的
// 可以按插入顺序访问每个元素
let set = new Set().add(3).add(1).add(4);

不过,可迭代对象不一定是集合对象,也可以是仅仅具有类似数组行为的其他数据结构,比如本章 开头提到的计数循环。该循环中生成的值是暂时性的,但循环本身是在执行迭代。计数循环和数组都具 有可迭代对象的行为。

任何实现 Iterable 接口的数据结构都可以被实现 Iterator 接口的结构“消费”(consume)。迭 代器(iterator)是按需创建的一次性对象。每个迭代器都会关联一个可迭代对象,而迭代器会暴露迭代 其关联可迭代对象的 API。迭代器无须了解与其关联的可迭代对象的结构,只需要知道如何取得连续的 值。

1. 可迭代协议:

实现 Iterable 接口(可迭代协议)要求同时具备两种能力:支持迭代的自我识别能力和创建实现 Iterator 接口的对象的能力。在 ECMAScript 中,这意味着必须暴露一个属性作为“默认迭代器”,而 且这个属性必须使用特殊的 Symbol.iterator 作为键。这个默认迭代器属性必须引用一个迭代器工厂 函数,调用这个工厂函数必须返回一个新迭代器。

很多内置类型都实现了 Iterable 接口:  字符串

  • 数组
  • 映射
  • 集合
  • arguments 对象
  • NodeList 等 DOM 集合类型

检查是否存在默认迭代器属性可以暴露这个工厂函数:

let num = 1;
let obj = {};
// 这两种类型没有实现迭代器工厂函数 console.log(num[Symbol.iterator]); // undefined console.log(obj[Symbol.iterator]); // undefined
let str = 'abc';
let arr = ['a', 'b', 'c'];
let map = new Map().set('a', 1).set('b', 2).set('c', 3);
let set = new Set().add('a').add('b').add('c');
let els = document.querySelectorAll('div');
// 这些类型都实现了迭代器工厂函数 console.log(str[Symbol.iterator]); // f values() { [native console.log(arr[Symbol.iterator]); // f values() { [native console.log(map[Symbol.iterator]); // f values() { [native console.log(set[Symbol.iterator]); // f values() { [native console.log(els[Symbol.iterator]); // f values() { [native
// 调用这个工厂函数会生成一个迭代器 console.log(str[Symbol.iterator]()); // StringIterator {} console.log(arr[Symbol.iterator]()); // ArrayIterator {} console.log(map[Symbol.iterator]()); // MapIterator {} console.log(set[Symbol.iterator]()); // SetIterator {} console.log(els[Symbol.iterator]()); // ArrayIterator {}

实际写代码过程中,不需要显式调用这个工厂函数来生成迭代器。实现可迭代协议的所有类型都会 自动兼容接收可迭代对象的任何语言特性。接收可迭代对象的原生语言特性包括:

  • for-of 循环
  • 数组解构
  • 扩展操作符
  • Array.from()
  • 创建集合
  • 创建映射
  • Promise.all()接收由期约组成的可迭代对象
  • Promise.race()接收由期约组成的可迭代对象
  • yield*操作符,在生成器中使用 这些原生语言结构会在后台调用提供的可迭代对象的这个工厂函数,从而创建一个迭代器: