Skip to content

在 ES 6 中规定,如果一个对象具有 Symbol.iterator 这个属性,并且属性值是一个迭代器创建函数,那么我们称这个对象是可迭代的,这就是迭代器协议。

在 JS 中,数组其实就是一个典型的可迭代对象,我们可以用下面的方式验证:

js
/**
 * 遍历一个数组并打印每个元素的值。
 * 该代码不作为函数执行,而是直接在全局作用域中运行。
 * 没有参数和返回值,因为它直接操作全局变量。
 */
const arr = [1, 2, 3, 4, 5]; // 定义一个包含1到5的数组
const iterator = arr[Symbol.iterator](); // 获取数组的迭代器
let data = iterator.next(); // 获取迭代器的第一个元素
while (!data.done) { // 当数据未遍历完时继续循环
	console.log(data.value); // 打印当前遍历到的元素的值
	data = iterator.next(); // 获取迭代器的下一个元素
}

除了数组以外,很多伪数组其实 JS 都给我们做成了一个可迭代的对象,例如我们通过 document.querySelectorAll() 得到的伪数组,就是可迭代的,这一点读者可以自行验证。

有了迭代器,我们就可以很方便地遍历一个可迭代对象,但是有一个问题,这个遍历的算法需要我们自己写,我们需要自己调用该对象上的迭代器创建函数创建一个迭代器,然后使用循环对这个迭代器进行遍历,我们会发现这个过程非常机械通用,只要我们按照这个流程可以遍历所有可遍历对象,但是每次写一遍又很麻烦,所以 ES 6 提供了 for...of 循环来帮助我们干这个事。

js
const arr = [1,2,3,4,5];
for(const item of arr){
	console.log(item);
}

这样就可以很方便的实现数组遍历。

注意 for...of 和 for...in 的区别,for...in 是遍历属性列表,是可以拿到原型链的,也就是说 for...in 本质上用的并不是迭代器,但是 for...of 本质上用的就是迭代器实现的,实际上就是一个语法糖。综上所述,for...of 只能遍历可迭代对象,但是 for...in 可以遍历所有对象。当然,除此之外,两者最大的区别其实是一个拿 key,一个拿 value

属性描述符中的enumerable 是指可遍历,而非可迭代。

展开运算符补充

展开运算符可以作用于可迭代对象,只要一个对象是可迭代的,那么一定可以展开,通过这种方式,其实可以将可迭代对象很方便地转换为数组,实际上展开运算符用的就是迭代器。

以笔记为镜,可以知得失