这几天研究了一下迭代器模式,期间有一段时间经常搞不太懂一些概念与概念之间的关系,今天来整理一下。
迭代的一些基本概念
- 循环是迭代机制的基础
- 迭代在一个有序集合上进行
- 按照顺序反复多次执行一段程序,通常会有明确的终止条件
我的理解:
实际上就是为了优化循环,各种数据结构的循环。而且各种数据结构循环起来可以千奇百怪,为了合理的统一,就有了迭代器模式。
关键词
- 可迭代对象
- 可迭代协议(
Iterable
接口)
- 迭代器
- 迭代器协议(
Iterator
接口)
- 迭代器对象(
IteratorResult
)
关系图

QA式学习
Q:什么是可迭代对象?
A:满足可迭代协议(实现Iterable
接口)的对象。
Q:可迭代协议是啥?
A:就是Iterable
接口。满足可迭代协议的对象应该满足以下条件:
- 能够创建实现了
Iterator
接口的对象(实际上就是迭代器)
- 且可以通过迭代器
Iterator
消费。
举个例子,数组,集合,映射等等都满足可迭代协议。他们都可以用for...of
遍历。
Q:什么是消费?
A:可以理解为遍历。有一个相关的概念“耗尽”,可以理解为遍历结束了。
Q:怎么满足可迭代协议?
A:你的对象需要有一个键名为Symbol.iterator
的属性,指向一个迭代器工厂函数。啥意思嘞?就是说
//jojo是一个可迭代对象(数组)
console.log(jojo[Symbol.iterator]); // ƒ values() { [native code] }
作为一个工厂函数,我们调用它的话就应该可以生成一个迭代器
console.log(jojo[Symbol.iterator]()); //Array Iterator {}
Q:什么是迭代器?
A:首先,迭代器是用于迭代与其关联的对象的一次性使用对象,迭代器满足迭代器协议(实现Iterator
接口)。一次性是指其在完成一次遍历(消费)之后就会被“耗尽”,这个时候再想遍历只能通过重新生成一个迭代器。
Q:迭代器协议说了啥?
A:迭代器协议说,只要你实现了Iterator
接口,你就是个迭代器辣!你至少需要有一个next()
方法来返回一个迭代器对象IteratorResult
。这个对象包含两个属性:done
和value
。其中done
为一个布尔值,当done
不为真时表示还可以通过调用next()
取得下一个值,当done
为真时,就可以被称为“耗尽”了。当done
不为真时,value
对象表示可迭代对象的下一个值,而当done
不为真时,value
就自然为undefined
了。
模拟for...of
在MDN上有这么一段话
大意
for...of
语句为可迭代对象创建循环迭代。这些可迭代对象包括内置的String
,Array
,和一些类数组对象(比如arguments
和NodeList
),TypedArray
,Map
,Set
和用户定义的可迭代对象。
也就是说实际上使用for...of
来遍历正是迭代器模式的一个应用。通过模拟一个数组的for...of
遍历来更好地理解一下迭代器。
当我们普普通通for..of
的时候发生了甚么事呢?
let arr = [1,2,3,4,5];
for(let item of arr)
console.log(item);
实际上上面的代码可以等价于下面的代码。
let arr = [1,2,3,4,5];
let it = arr[Symbol.iterator]();//it->迭代器,通过调用arr[Symbol.iterator]()来生成
let item = it.next();//item->迭代器对象,包含着done和value两个属性
while(!item.done) {//当迭代器没有耗尽时
console.log(item.value);//可以通过item.value来访问当前迭代到的值
item = it.next();//继续迭代
}
自定义迭代器
刚刚提到了,for...of
同样可以用于遍历用户定义的可迭代对象。一般的可迭代对象是不可以用for...of
来遍历的,但是我们可以通过改造我们的对象,使其满足可迭代协议来使用for...of
let colors = {
blue : "蓝色",
green : "绿色",
yellow : "黄色"
};
for(let color of colors)
console.log(color);

现在我们让color对象满足Iterable
接口
colors[Symbol.iterator] = function() {
let keys = Object.keys(colors);
let index = 0;
return {
next : function() {
if (index < keys.length) {
return {
value : colors[keys[index++]],
done : false
}
}
return { done : true }
}
}
}
然后再次for...of
循环,可以发现没有报错,并且正常循环输出了。

以上就是我对迭代器的一些理解,如果有什么问题欢迎指正!