Iterator 与 Iterable
迭代器(Iterator)
-
迭代器是一个对象,它提供了一种方法来顺序访问一个集合(或称为“序列”)中的元素,且使用该接口时无需关心对象内部实现的细节 → 即: 帮助我们对某个数据结构进行遍历的对象
-
在 JavaScript 中,迭代器也是一个具体的对象,该对象需要符合迭代器的协议(iterator protocol) → 在 JavaScript 这个标准就是需要由一个特定的 next 方法(↓)
-
next 方法的要求:
该方法返回一个对象,该对象包含如下两个属性
value:
表示某个序列中的下一个值
done:
一个 boolean 值,表示是否已经完成了所有遍历
-
代码示例
-
基本使用
-
const arr = [1, 2, 3] let index = 0 const arrIterator = { next() { // -- 特定的 next 方法 if (index < arr.length) return { value: arr[index++], done: false } else return { value: undefined, done: true } } }
-
+ TEST console.log(arrIterator.next()) // { value: 1, done: false } console.log(arrIterator.next()) // { value: 2, done: false } console.log(arrIterator.next()) // { value: 3, done: false } console.log(arrIterator.next()) // { value: undefined, done: true } console.log(arrIterator.next()) // { value: undefined, done: true }
-
-
生成数组迭代器的方法封装(练习)
-
+ 方法封装 function createArrayIterator(arr) { let [index, len] = [0, arr.length] return { // -- 返回对应 arr 数组的迭代器对象 next() { if (index < len) return { value: arr[index++], done: false } else return { value: undefined, done: true } } } }
-
+ TEST const arr = [1, 2, 3] const arrIterator = createArrayIterator(arr) // -- 创建 arr 数组的迭代器对象 console.log(arrIterator.next()) // { value: 1, done: false } console.log(arrIterator.next()) // { value: 2, done: false } console.log(arrIterator.next()) // { value: 3, done: false } console.log(arrIterator.next()) // { value: undefined, done: true } console.log(arrIterator.next()) // { value: undefined, done: true }
-
-
可迭代对象(Iterable)
-
**可迭代对象是指那些内置了
Symbol.iterator
方法的对象 → 当一个对象是一个可迭代对象时,我们就可以对其进行某些迭代操作(如 for … of 操作等) ** -
任何具有
Symbol.iterator
方法的对象都被认为是可迭代的(该方法需要返回一个迭代器对象) -
如: 我们可以通过一个类数组的例子来进行示例
-
+ 1. 引入: 通常一个数组我们是可以直接通过扩展运算符(...),将一个数组中的元素浅拷贝到另一个数组中的 const arr = [1, 2, 3, 4] console.log([...arr]) // [1, 2, 3, 4]
-
+ 2. 但如果是一个类数组呐(类数组: 具有索引和值 & 具有 length 属性) const likeArray = { 0: 1, 1: 2, 2: 3, length: 3 } // 报错: 对于数组来说,它们内置支持迭代器协议,因此可以直接使用扩展运算符来展开数组的元素 / 但对应该类数组来说,并没有实现对应的迭代器协议 console.log([...likeArray]) // TypeError: likeArray is not iterable
-
+ 3. 我们可以通过给该 likeArray 数组,添加一个 Symbol.iterator 方法,来使其变成可迭代对象 → 可以像数组那样也使用扩展运算符 const likeArray = { // 类数组: 具有索引和值 & 具有 length 属性 0: 1, 1: 2, 2: 3, length: 3, [Symbol.iterator]() { // -- 定义特定的 Symbol.iterator 方法,使其变成一个可迭代对象 let idx = 0 return { // -- Symbol.iterator 方法需要返回一个迭代器对象 next: () => { // -- tip: 该 next 方法需要使用箭头函数,因为需要拿到上层作用域的 this 指向,即 likeArray 执行上下文(当然也可以在 Symbol.iterator 中提前见 this 通过变量存储起来) if (idx < this.length) return { value: this[idx++], done: false } else return { value: undefined, done: true } } } } } // 此时,我们再通过扩展运算符来浅拷贝 likeArray 是,就可以正常展开了 console.log([...likeArray]) // [1, 2, 3, 4]
-
-
原生的可迭代对象:
-
如
Array
、Map
、Set
、String
、TypedArray
、NodeList
对象等都是可迭代的 -
+ 我们可以通过可迭代对象中的 Symbol.iterator 方法获取对应的迭代器 const arr = [1, 2, 3] // -- 🔺因为数组本身就是一个可迭代对象,所以其内部肯定会有 Symbol.iterator 方法 const it = arr[Symbol.iterator]() // -- 我们可以直接执行数组中的 Symbol.iterator,来获取对应的迭代器对象 console.log(it.next()) // { value: 1, done: false } console.log(it.next()) // { value: 2, done: false } console.log(it.next()) // { value: 3, done: false } console.log(it.next()) // { value: undefined, done: true }
-
-
常见场景
- 遍历集合:使用
for...of
循环遍历数组、字符串、Map、Set等集合 - 生成器函数:生成器函数(function*)自动成为可迭代对象,并返回一个迭代器,用于按需生成序列中的值
- 自定义迭代逻辑:通过实现
Symbol.iterator
方法,可以为自定义对象添加迭代能力,使其能够使用for...of
循环遍历
- 遍历集合:使用