迭代器与生成器之必读篇

215 阅读3分钟

首先先来了解一下迭代,循环是迭代机制的基础,这是因为它可以指定迭代的次数,以及每次迭代要执行什么操作,每次循环都会在下一次迭代开始之前完成,而每次迭代的顺序都是事先定义好的,通常会有明确的终止条件。

在之前的版本,执行迭代必须使用循环或者其他的辅助结构,代码量增加,混乱,之后通过迭代模式解决这些问题,在ECMAScript6之后也支持了迭代模式。

迭代模式即可以把有些结构称为‘可迭代对象’(即理解为数组或者集合这样的集合类型的对象),因为他们实现了正式的Iterable接口,而且可以通过迭代器Iterator消费。

迭代器是按需创建的一次性对象,每个迭代器都会关联一个可迭代对象,而迭代器会暴露迭代其关联可迭代对象的API,迭代器无需了解与其关联的可迭代对象的结构,只需知道如何取得连续的值。

迭代器

1.可迭代协议  

   很多内置类型都实现了Iterable接口:

字符串
数组
映射
集合
arguments对象
NodeListDom集合类型

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()

都可以用于强制生成器进入关闭状态。