js 迭代器模式
迭代器模式(特别是在 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*操作符,在生成器中使用 这些原生语言结构会在后台调用提供的可迭代对象的这个工厂函数,从而创建一个迭代器:
推荐阅读
-
Web Hid Api 浏览器读取 IC 卡号 Js 源代码,无需插件支持
-
[Java 并发编程 III] 多线程案例(手撕单件模式、阻塞队列、定时器、线程池)
-
VIII.STM32F103 定时器触发器模式
-
如何遍历 python 迭代器
-
python 的迭代器和生成器有什么区别?
-
LeetCode 问题练习与摘要:窥视迭代器 - 284 - 输入: ["PeekingIterator"、"next"、"peek"、"next"、"next"、"hasNext"] [[[1, 2, 3]], , , , , , ] 输出: [空,1,2,2,3,false] 说明: PeekingIterator peekingIterator = new PeekingIterator([1, 2, 3]); // [1,2,3]. peekingIterator.next; // 返回 1,指针移动到下一个元素 [1,2,3]. peekingIterator.peek; // 返回 2,指针没有移动 [1,2,3] peekingIterator.next; // 返回 2,指针移动到下一个元素 [1,2,3] peekingIterator.next; // 返回 3,指针移动到下一个元素 [1,2,3] peekingIterator.hasNext; // 返回 False 小贴士
-
Webpack 模式 - 解决 - 本地服务器
-
Autosar CP 系列:传感器/执行器设计模式
-
JS 桥接模式的设计模式:构建跨维度的路径
-
介绍Video.js:一个免费的视频播放器