什么是迭代?
for(let i = 1; i <= 10; ++i) {
console.log(i);
}
看上面的一个数组循环,这是一个最基本的迭代。这种迭代需要事先知道数组的数据结构和使用,并且没有办法标识迭代何时终止。
es6为了解决这个问题,支持了迭代器模式
迭代器模式
迭代器模式 描述了一个方案,即可以把有些结构称为“可迭代对象”, 它们实现了 Iterable 接口。
在es6中,暴露了一个属性作为“默认迭代器”, 这个属性必须使用 Symbol.iterator作为健。
以下内置类型都实现了迭代器接口
- 字符串
- 数组
- 映射
- 集合
- arguments对象
- NodeList等DOM集合类型
不需要显示的调用这个工厂函数来生成迭代器,下列语法结构支持迭代。
- for-of 循环
- 数组解构
- 扩展操作符
- Array.from()
- 创建集合
- 创建映射
- Promise.all()
- Promise.race()
- yield* 操作符
let arr = ['foo','bar','baz'];
// for-of 循环
for (let el of arr) {
console.log(el);
}
// foo
// bar
// 数组解构
let [a,b,c] = arr;
console.log(a,b,c); //foo,bar,baz
// 扩展操作符
let arr2 = [...arr];
console.log(arr2); // ['foo','bar','baz']
// Array.from();
let arr3 = Array.from(arr);
console.log(arr3); // ['foo','bar','baz']
// set构造函数
let set = new Set(arr);
console.log(set); // Set(3){'foo','bar','baz'}
// Map构造函数
let pairs = arr.map((x,i) => [x,i]);
console.log(pairs); // [['foo',0],['bar',1],['baz',2]]
let map = new Map(pairs);
console.log(map); // Map(3) {'foo'=> 0, 'bar'=>1, 'baz'=>2}
迭代器协议
迭代器是一种一次性使用的对象,使用 next() 方法在可迭代对象中遍历数据。
next()方法返回的迭代器对象IteratorResult包含两个属性: done 和 value。
done是一个布尔值,表示是否还可以迭代。
value是可迭代对象的下一个值。
let arr = ['foo'];
let iter = arr[Symbol.iterator]();
console.log(iter.next()); // { done: false, value: 'foo' }
console.log(iter.next()); // { done: true, value: undefined }
console.log(iter.next()); // { done: true, value: undefined }
console.log(iter.next()); // { done: true, value: undefined }
自定义迭代器
class Counter{
constructor() {}
[Symbol.iterator]() {
return {
next() {
return {done: false, value: xxx}
}
}
}
}
生成器
生成器是新增的结构,拥有在一个函数块内暂停和恢复代码执行的能力。
function * generratorFn() {}
class Foo {
*generatorFn() {}
* generatorFn2() {}
}
生成器对象一开始处于暂停执行的状态 suspended 与迭代器相似,生成器也实现了Iterator接口,因此具有next()方法。
生成器对象可以通过 yield 中断执行。
可以通过yield 实现输入和输出
function* generatorFn() {
return yield 'foo';
}
let generatorObject = generatorFn();
console.log(generatorObject.next()); // { done: false, value: 'foo' }
console.log(generatorObject.next('bar')); // { done: true, value: 'bar' }
可以用 * 号增强 yield的行为,产生一个可迭代对象。
function* generatorFn() {
yield* [1, 2, 3];
}
let generatorObject = generatorFn();
for (const x of generatorFn()) {
console.log(x);
}
生成器作为默认迭代器
因为生成器实现了Iterable接口,所以生成器可以作为对象的默认迭代器
class Foo{
constructor() {
this.values = [1,2,3]
}
* [Symbol.iterator]() {
yield *this.values;
}
}
const f = new Foo();
for (let v of f) {
console.log(v);
}
提前终止生成器
- return
- throw
function* generatorFn() {
for (const x of [1, 2, 3]) {
yield x;
}
}
const g = generatorFn();
console.log(g); // generatorFn {<suspended>}
console.log(g.return(4)); // { done: true, value: 4 }
console.log(g.throw('xxx)) //
console.log(g);