Symbol.iterator 遍历器接口
共 1937字,需浏览 4分钟
·
2022-11-09 05:50
Iterator(遍历器)的概念
JavaScript 原有的表示“集合”的数据结构,主要是数组(Array)和对象(Object),ES6 又添加了Map和Set。
[
[1, 2],
{a: 1, b: 2},
new Set([1, 2]),
new Map([['a',1],['b',2]])
]
这样就有了四种数据集合,用户还可以组合使用它们,定义自己的数据结构,比如数组的成员是Map,Map的成员是对象。这样就需要一种统一的接口机制,来处理所有不同的数据结构。
遍历器(Iterator)就是这样一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。
Iterator 的作用有三个:一是为各种数据结构,提供一个统一的、简便的访问接口;二是使得数据结构的成员能够按某种次序排列;三是 ES6 创造了一种新的遍历命令for...of循环,Iterator 接口主要供 for...of 消费。
当使用 for...of 循环遍历某种数据结构时,该循环会自动去寻找 Iterator 接口。
ES6 规定,默认的 Iterator 接口部署在数据结构的 Symbol.iterator 属性,或者说,一个数据结构只要具有 Symbol.iterator 属性,就可以认为是“可遍历的”。
一个对象如果要具备可被 for...of 循环调用的 Iterator 接口,就必须在Symbol.iterator的属性上部署遍历器生成方法。
let obj = {
0: 1,
1: 2,
2: 3,
length: 3,
[Symbol.iterator] () {
let that = this;
let len = 0;
return {
next () {
return {done: len === that.length, value: that[len++]}
}
}
}
}
for (const i of obj) {
console.log(i)
}
有了遍历器接口,数据结构就可以用 for...of 循环遍历,也可以使用 while 循环遍历。遍历器对象每次移动指针(next方法),都检查一下返回值的 done 属性,如果遍历还没结束,就移动遍历器对象的指针到下一步(next方法),不断循环。
原生具备 Iterator 接口的数据结构如下。
Array
Map
Set
String
TypedArray
函数的 arguments 对象
NodeList 对象
下面的例子是数组的 Symbol.iterator 属性。
let arr = ['a', 'b', 'c'];
let iter = arr[Symbol.iterator](); // 遍历器对象(即指针对象)
iter.next() // { value: 'a', done: false } // 指针对象的next方法,用来移动指针。
iter.next() // { value: 'b', done: false } // 这个对象具有value和done两个属性
iter.next() // { value: 'c', done: false }
iter.next() // { value: undefined, done: true }
调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,也就是上面介绍的遍历器对象(Iterator Object)。
let obj = {
0: 1,
1: 2,
2: 3,
length: 3,
[Symbol.iterator]: function * gen () {
let len = 0
while (len < this.length) {
yield this[len++]
}
}
}
for (const i of obj) {
console.log(i)
}
总结:
遍历器它是一种接口,为各种不同的数据结构提供统一的访问机制。
Symbol.iterator 属性的数据结构,就称为部署了遍历器接口。调用这个接口,就会返回一个遍历器对象。
遍历器对象上每次调用 next 方法,都会返回一个代表当前成员的信息对象,具有 value 和 done 两个属性。
调用 Generator 函数后,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,也就是遍历器对象。