1. 解释
迭代器是一种特殊对象,它符合迭代器协议规范。在 TypeScript 中,我们可以定义一个接口,这个接口上有一个函数类型 next
,next()
方法的返回值类型是 { value: any, done: boolean }
。其中,value
是 any 类型,表示下一个将要返回的值;done
是布尔类型,当没有更多可返回数据时返回 true。迭代器还会保存一个内部指针,用来指向当前集合中值的位置。
迭代器一旦创建,迭代器对象就可以通过重复调用 next()
显式地迭代。
2. 模拟一个简略的迭代器
代码解释:
第 1 行,声明了一个 Iterator 接口,具有 next 这样一个函数类型。
第 8 行,声明了一个可以返回迭代器对象的函数,这个函数的返回值类型必须符合 Iterator 接口。
倒数第 4 行,通过调用迭代器对象上的 next() 方法,可以拿到数据集中的下一个数据项。
最后一行,拿到数据集中的所有数据后,done 属性变为 true。
3. 可迭代性
上面的例子,用模拟的迭代器地迭代了一个数组对象,那是不是所有的对象都可以这样迭代呢?当然不是。
只有一个对象实现了 Symbol.iterator
属性时,我们才认为它是可迭代的。一些内置的类型如 Array,Map,Set,String,Int32Array,Uint32Array
等都已经实现了各自的 Symbol.iterator
。
Symbol.iterator
属性本身是一个函数,就是当前数据结构默认的迭代器生成函数。执行这个函数,就会返回一个迭代器。
比如,String
是一个内置的可迭代对象:
- 1
- 2
String
的默认迭代器会依次返回该字符串的字符:
代码解释:
第 1 行,声明一个字符串类型变量,字符串类型内置了默认迭代器生成函数 Symbol.iterator
。
第 2 行,执行这个函数,返回了一个迭代器。
总结一下迭代器的作用:
- 为各种数据结构(Array,Map,Set,String等),提供一个统一的、简便的访问接口。
- 使得数据结构的成员能够按某种次序排列。
- 创造了一种新的遍历命令
for..of
循环。
4. for…of
for...of
会遍历可迭代的对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等),调用对象上的 Symbol.iterator
方法。
4.1 迭代数组
解释: 通过 for...of
循环遍历数组 iterable
的每一项元素。
解释: 通过 let { name } of heroes
循环迭代 heroes
对象数组,将每一个对象解构,得到每一个对象的 name
属性值。
4.2 迭代字符串
字符串具有可迭代性,通过 for...of
可以快速遍历出每一个字符。
4.3 迭代 Map:
解释: 一个 Map 对象在迭代时会根据对象中元素的插入顺序来进行。for...of
循环在每次迭代后会返回一个形式为 [key,value]
的数组。通过使用 let [key, value]
这种解构形式,可以快速获取每一项属性值。
5. for…of 与 for…in 的区别
for...of
语句遍历可迭代对象定义要迭代的数据。for...in
语句以任意顺序迭代对象的可枚举属性。
for...in
可以操作任何对象,迭代对象的可枚举属性。但是 for...of
只关注于可迭代对象的值。
6. 解构赋值与扩展运算符
对数组和 Set 结构进行解构赋值时,会默认调用 Symbol.iterator 方法:
- 1
- 2
扩展运算符也会调用默认的 Iterator 接口,得到一个数组结构:
- 1
- 2
7. 小结
本小节介绍了迭代器的一些具体使用,要注意 for...of
与 for...in
的区别。
另外,可以借助编辑器(如 vscode
)查看一下 TypeScript 迭代器接口定义的源码:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22