Iterator
(迭代器)是 ES6 引入的一种 接口,用于 顺序访问 可迭代对象(Array
、Set
、Map
、String
、arguments
、自定义对象等)。
Iterator(迭代器)的作用有三个:
- 为各种数据结构提供一个统一的、简便的访问接口
- 使数据结构的成员能够按某种次序排列
- ES6 创造了一种新的遍历命令 for…of 循环,Iterator 接口主要供 for…of 消费
1. 迭代器的基本概念
(1) 迭代器是什么?
迭代器是一种 特殊对象,提供 next()
方法,每次调用都会返回:
1 | { value: 当前值, done: 是否完成 } |
当 done: true
时,表示迭代结束。
Iterator 的遍历过程
1 2 3 4 5 6 7 8 9 10 | // Iterator 的遍历过程如下: 1. 创建一个指针对象,指向当前数据结构的起始位置 2. 第一次调用指针对象的 next 方法,可以将指针指向数据结构的第一个成员 3. 第二次调用指针对象的 next 方法,指针就指向数据结构的第二个成员 4. 不断调用指针对象的 next 方法,直到它指向数据结构的结束位置 // 每一次调用 next 方法,都会返回一个包含 value 和 done 两个属性的对象 { value: 当前成员的值, done: 布尔值,表示遍历是否结束 } |
2. 生成迭代器
(1) 手动创建迭代器
1 2 3 4 5 | function createIterator(arr) { let index = 0; return { next: function () { return index |
每次
next()
调用,都会返回 value
并前进。
(2) 使用 Symbol.iterator
所有 可迭代对象(Array
、Set
、Map
等)都有 默认的迭代器,可以用 Symbol.iterator
访问:
1 2 3 4 5 6 | let arr = [ "x" , "y" , "z" ]; let iterator = arr[Symbol.iterator](); console.log(iterator.next()); // { value: 'x', done: false } console.log(iterator.next()); // { value: 'y', done: false } console.log(iterator.next()); // { value: 'z', done: false } console.log(iterator.next()); // { value: undefined, done: true } |
数组、字符串、Set、Map 都有
Symbol.iterator
,可直接迭代。
(3) 自定义对象的迭代器
普通对象没有默认迭代器,需手动实现:
1 2 3 4 5 6 7 | let myObj = { data: [10, 20, 30], [Symbol.iterator]: function () { let index = 0; return { next: () => { return index |
对象没有默认迭代器,需实现
Symbol.iterator
才能用 for...of
。
3. for…of 遍历迭代器
所有 实现 Symbol.iterator
的对象,都可以用 for...of
遍历:
1 2 3 4 5 6 7 | let arr = [ "A" , "B" , "C" ]; for ( let char of arr) { console.log(char); } // A // B // C |
相比
forEach()
,for...of
可与 break
、continue
配合使用。
4. 可迭代对象
可以使用 for...of
、Symbol.iterator
的对象
Array
String
Set
Map
arguments
NodeList
- 自定义对象(需实现
Symbol.iterator
)
5. Set 和 Map 的迭代器
(1) Set
迭代
1 2 3 4 5 6 | let mySet = new Set([ "apple" , "banana" , "cherry" ]); let setIter = mySet[Symbol.iterator](); console.log(setIter.next()); // { value: 'apple', done: false } console.log(setIter.next()); // { value: 'banana', done: false } console.log(setIter.next()); // { value: 'cherry', done: false } console.log(setIter.next()); // { value: undefined, done: true } |
Set
按插入顺序存储,迭代返回唯一值。
(2) Map
迭代
1 2 3 4 5 6 7 8 9 | let myMap = new Map([ [ "name" , "Alice" ], [ "age" , 25] ]); for ( let [key, value] of myMap) { console.log(key, value); } // name Alice // age 25 |
Map
迭代时返回 [key, value]
数组。
6. 迭代器 vs 生成器
特性 | 迭代器 (Iterator) | 生成器 (Generator) |
---|---|---|
创建方式 | 手动实现 next()
|
function* 生成 |
使用 Symbol.iterator
|
需要手动实现 | 生成器自动实现 |
可暂停执行 | yield ) |
示例:生成器
1 2 3 4 5 6 7 8 9 10 | function * generatorFunction() { yield "A" ; yield "B" ; yield "C" ; } let gen = generatorFunction(); console.log(gen.next()); // { value: 'A', done: false } console.log(gen.next()); // { value: 'B', done: false } console.log(gen.next()); // { value: 'C', done: false } console.log(gen.next()); // { value: undefined, done: true } |
生成器更简洁,支持
yield
暂停执行。
7. Iterator 使用场景
7.1 解构赋值
1 2 3 | // 对数组和 Set 结构进行解构赋值时,会默认调用 Iterator 接口 let set = new Set().add( 'a' ).add( 'b' ).add( 'c' ); let [x, y] = set; // x='a'; y='b' |
7.2 扩展运算符
1 2 3 4 5 6 | // 扩展运算符(...)也会调用默认的 Iterator 接口 let str = 'hello' ; [...str] // ['h', 'e', 'l', 'l', 'o'] let arr = [ 'b' , 'c' ]; [ 'a' , ...arr, 'd' ] // ['a', 'b', 'c', 'd'] |
7.3 yield*
1 2 3 4 5 6 7 8 9 10 | // yield* 后面跟的是一个可遍历的结构,它会调用该结构的遍历器接口 let generator = function * () { yield 1; yield * [2, 3, 4]; yield 5; }; for ( let v of generator()) { console.log(v); } // 1, 2, 3, 4, 5 |
8. 注意事项
8.1 对象的 for…of 循环
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // 对象默认不具备 Iterator 接口,不能直接使用 for...of let obj = { a: 1, b: 2, c: 3 }; for ( let value of obj) { console.log(value); // TypeError: obj is not iterable } // 正确的遍历对象方式 // 1. 使用 Object.keys() for ( let key of Object.keys(obj)) { console.log(key + ': ' + obj[key]); } // 2. 使用 Object.entries() for ( let [key, value] of Object.entries(obj)) { console.log(key + ': ' + value); } |
8.2 Iterator 接口与 Generator 函数
1 2 3 4 5 6 7 8 9 10 11 12 | // 使用 Generator 函数实现 Iterator 接口 let obj = { *[Symbol.iterator]() { yield 'hello' ; yield 'world' ; } }; for ( let x of obj) { console.log(x); } // hello // world |
9. 最佳实践
9.1 为类部署 Iterator 接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | class Collection { constructor() { this .items = []; } add(item) { this .items.push(item); } *[Symbol.iterator]() { for ( let item of this .items) { yield item; } } } let collection = new Collection(); collection.add( 'foo' ); collection.add( 'bar' ); for ( let value of collection) { console.log(value); } // foo // bar |
9.2 异步迭代器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // ES2018 引入了异步迭代器 const asyncIterable = { async *[Symbol.asyncIterator]() { yield 'hello' ; yield 'async' ; yield 'iteration' ; } }; ( async () => { for await (const x of asyncIterable) { console.log(x); } })(); // hello // async // iteration |
10. 适用场景
适用于
遍历数组、字符串、Set、Map自定义可迭代对象流式处理数据(类似分页加载)避免一次性加载大数据(生成器)
11. 总结
-
Iterator
是 ES6 提供的一种接口,用于顺序访问集合。 -
Symbol.iterator
让对象变成可迭代,可用于for...of
、spread
。Set
、Map
、Array
、String
默认实现Symbol.iterator
,可直接迭代。 - 生成器 (
Generator
) 自动创建迭代器,可暂停执行 (yield
),更强大。
到此这篇关于ES6 迭代器 Iterator使用总结的文章就介绍到这了,更多相关ES6 迭代器 Iterator使用内容请搜索IT俱乐部以前的文章或继续浏览下面的相关文章希望大家以后多多支持IT俱乐部!