首先先来了解一下迭代,循环是迭代机制的基础,这是因为它可以指定迭代的次数,以及每次迭代要执行什么操作,每次循环都会在下一次迭代开始之前完成,而每次迭代的顺序都是事先定义好的,通常会有明确的终止条件。
在之前的版本,执行迭代必须使用循环或者其他的辅助结构,代码量增加,混乱,之后通过迭代模式解决这些问题,在ECMAScript6之后也支持了迭代模式。
迭代模式即可以把有些结构称为‘可迭代对象’(即理解为数组或者集合这样的集合类型的对象),因为他们实现了正式的Iterable接口,而且可以通过迭代器Iterator消费。
迭代器是按需创建的一次性对象,每个迭代器都会关联一个可迭代对象,而迭代器会暴露迭代其关联可迭代对象的API,迭代器无需了解与其关联的可迭代对象的结构,只需知道如何取得连续的值。
迭代器
1.可迭代协议
很多内置类型都实现了Iterable接口:
字符串
数组
映射
集合
arguments对象
NodeList等Dom集合类型
2.接收可迭代对象的原生语言特性包括
for-of循环
数组结构
扩展操作符
Array.from()
创建集合
创建映射
Promise.all()
Promise.race()
yield*操作符,在生成器中使用
这些原生语言结构会在后台调用提供的迭代对象的这个工厂函数,从而创建一个迭代器
例如:
let arr = ['aaa','bbb','ccc'];
//for of循环
for(let item of arr){console.log(item);} // aaa bbb ccc;
//数组结构
let [d,e,f] = arr;
console.log(d,e,f); //aaa bbb ccc;
//扩展运算符
let arr2 = [...arr];
console.log(arr2); //['aaa','bbb','ccc'];
//Array.from()
let arr3 = Array.from(arr);
consoel.log(arr3); // ['aaa','bbb','ccc']
//Set构造函数
let arr4 = new Set(arr);
console.log(arr4) ; //{'aaa','bbb','ccc'}
3.迭代器协议
迭代器是一种一次性使用的对象,用于迭代与其关联的可迭代对象,迭代器API使用next()方法,在可迭代对象中遍历数据。当done为true状态称为"耗尽"
可迭代对象
let arr = ['aaa','bbb'];
迭代器工厂函数
console.log(arr[Symbol.iterator]); // ƒ values() { [native code] }
迭代器
let item = arr[Symbol.iterator]();
console.log(item); // Array Iterator {};
执行迭代
console.log(item.next()); // {value: "aaa", done: false};
console.log(item.next()); // {value: "bbb", done: false};
console.log(item.next()); // {value: undefined, done: true};
迭代器维护着一个指向可迭代对象的引用,因此迭代器会阻止垃圾回收程序回收可迭代对象。
4.提前终止迭代器
可用return()方法,提前关闭时执行的逻辑。
for-of循环通过break continue return throw提前退出;
解构操作并未消费所有值,通过return {done:true};来实现。
生成器
生成器时ECMAScript6新增的一个灵活的结构,拥有在一个函数块内暂停和恢复代码执行的能力。比如可以自定义迭代器和实现协程。
1.生成器基础
其形式是一个函数,函数名称前面加一个*表示他是一个生成器,只要可以定义函数的地方,就可以定义生成器
//生成器函数声明
function*kkb(){};
//生成器函数表达式
let kkb = function*(){};
//作为字面量方法的生成器的函数
let foo = {
*kkb(){};
};
//作为类实例方法的生成器函数
class Foo{
*kkb(){};
}
注释:箭头函数不能用来定义生成器函数
调用生成器函数会产生一个生成器对象,开始处于暂停执行的状态,因此也是通过调用next()方法,让生成器开始或者恢复执行。
function *kkb(){};
const k = kkb();
console.log(k);
console.log(k.next());
2.通过yield中断执行
function *foo(){
yield;
}
let foos = foo();
console.log(foos.next()); // {value: undefined, done: false}
console.log(foos.next()); // {value: undefined, done: true}
3.提前终止生成器
return()
throw()
都可以用于强制生成器进入关闭状态。