Open
Description
一、Iteration protocols
JS里可以通过for-in
遍历对象,for
遍历字符串和数组,并且数组还有独立的各种遍历方法。ES2015里又增加了一些数据集合(Set/Map/生成器函数)。为了对这些数据集合提供统一遍历方式引入了迭代协议。
迭代协议由两部分构成:
- 可迭代协议(iterable protocol)
- 迭代器协议(iterator protocol)
二、可迭代协议(iterable protocol) & 可迭代对象
2.1 可迭代协议(iterable protocol)
The iterable protocol allows JavaScript objects to define or customize their iteration behavior。
协议内容:
- 对象本身(或者原型链上)具有
Symbol.iterator
成员方法; Symbol.iterator
成员方法返回值是个迭代器。
通过名字也能看出Symbol.iterator
成员方法就是为了获取可迭代对象的迭代器的。
2.2 可迭代对象
实现了可迭代协议的对象叫可迭代对象。
2.3 可迭代对象的语法支持
1. for-of
遍历
for (let value of ['a', 'b', 'c']) {
console.log(value);
}
2. 展开语法...
console.log([...'abc']); // ["a", "b", "c"]
3. yield*
遍历
var gen = function* () {
yield 1;
yield* [12, 123];
return 3;
}
4. 解构赋值
var gen = function* () {
yield 1;
yield* [12, 123];
return 3;
}
var g = gen();
var [a, b, c] = g;
console.log(a, b, c); // 1 12 123
三、迭代器协议(iterator protocol)& 迭代器(iterator )
迭代器协议定义如何产生一系列值的标准方式(就像Promise/A+规范定义Promise对象)。
实现迭代器协议的对象叫迭代器。
3.1 协议内容
- 具有
next
成员方法; next
成员方法返回非null的对象,并且对象至少具有两个属性:
value
: 迭代器一系列值的具体一个值,done=true
时表示没有值了
此时忽略value
的值,这里经常误以为是最后一个值。上面列举的可迭代最新的遍历语法都会忽略done=true
的value
.done
: 标记是否还具有下个值。
这样就可以获取迭代器一系列的值以及判断是否还具有更多的值。
3.2 可迭代协议(iterable protocol)和迭代器协议(iterator protocol)对比
两者是不同的:
- 前者定义如何遍历一个对象;
- 后者定义如何产生遍历的一系列值。
一个对象可能既是可迭代对象,也可能是迭代器。
四、实战
4.2 内置可迭代对象
String
Array
,TypedArray
,Set
,Map
- 生成器
generator
对象 arguments
对象
内置可迭代对象返回的迭代器也是个可迭代对象
内置可迭代对象返回的迭代器也是个可迭代对象(额,有点绕~)并且两者的迭代器是相等的
const arr = [ 1, 2, 3 ]
const iter = arr[Symbol.iterator]()
for (const item of iter) {
console.log(item) // 1 2 3
}
const iter2 = iter[Symbol.iterator]()
console.log(iter === iter2) // true
const iter3 = iter[Symbol.iterator]()[Symbol.iterator]()[Symbol.iterator]()
console.log(iter === iter3) // true
4.3 自定义可迭代对象
var iterableName = {
[Symbol.iterator]: () => {
var index = 0;
var val = ['john', 'lucy']
return {
next: () => {
return val.length === index ? {
done: true
} : {
value: val[index++],
done: false
}
}
}
}
}
for(var a of iterableName) {
console.log(a)
}
// ['john', 'lucy']
[...iterable]
代码输出判断:
var a = {
[Symbol.iterator]: () => {
var index = 0;
return {
next: () => {
if(index === 3) {
return {
done: true,
value: 9
}
}
return {
done: false,
value: ++index
}
}
}
}
}
for(let v of a) {
console.log(v)
}