生成器和迭代器
文章推荐:https://juejin.cn/post/6844903717246861320#heading-0
迭代器
任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。
为各种数据结构,提供一个统一的、简便的访问接口;
使得数据结构的成员能够按某种次序排列
ES6创造了一种新的遍历命令for...of循环,Iterator接口主要供for...of消费。
原生具备iterator接口的数据
- Array
- set容器
- map容器
- String
- 函数的 arguments 对象
- NodeList 对象
迭代器的工作原理
- 创建一个指针对象,指向数据结构的起始位置。
- 第一次调用next方法,指针自动指向数据结构的第一个成员
- 接下来不断调用next方法,指针会一直往后移动,直到指向最后一个成员
- 每调用next方法返回的是一个包含value和done的对象,{value: 当前成员的值,done: 布尔值}
- value表示当前成员的值,done对应的布尔值表示当前的数据的结构是否遍历结束。
- 当遍历结束的时候返回的value值是undefined,done值为true
//手写一个迭代器 function Iterator(arr){ let index = 0; return { next:function(){ return index<arr.length?{value:arr[index++],done:false}:{value:undefined,done:true}; } } } let arr = [1,4,'abc']; let iterator = new Iterator(arr); console.log(iterator.next()); // {val:1,done:false} console.log(iterator.next()); // {val:4,done:false} console.log(iterator.next()); // {val:'abc',done:false} console.log(iterator.next()); // {val:undefined,done:true}
- 注意:当使用for of去遍历某一个数据结构的时候,首先去找Symbol.iterator,找到了就去遍历,没有找到的话不能遍历,提示
Uncaught TypeError: XXX is not iterable, 因此for of循环不支持遍历普通对象
生成器
推荐视频:https://www.bilibili.com/video/BV1Rp4y1v7AH?from=search&seid=10099126301110882575
概念
- Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同
- 语法上,首先可以把它理解成,Generator 函数是一个状态机,封装了多个内部状态。
- Generator 函数除了状态机,还是一个遍历器对象生成函数。
- 可暂停函数(惰性求值), yield可暂停,next方法可启动。每次返回的是yield后的表达式结果
特点
- function关键字与函数名之间有一个星号;
- 函数体内部使用yield表达式,定义不同的内部状态
(大白话解释就是生成函数要加*,能用yield暂停函数执行,能用next继续启动,是不是很像迭代器。我们可以把yield看成播放器暂停,next看成继续播放)
function* generatorExample(){ console.log("开始执行") yield 'hello'; yield 'generator'; return 'complete' } // generatorExample() // 这种调用方法Generator 函数并不会执行 let MG = generatorExample() // 返回指针对象 MG.next() //开始执行 {value: "hello", done: false} MG.next() //开始执行 {value: "generator", done: false} MG.next() //开始执行 {value: "complete", done: true}
- 作用域独立
function* xxfn(){ var n = 1; yield ++n; yield ++n; yield ++n; } var aa = xxfn(); var bb = xxfn(); //aa,bb两个迭代器作用域独立
.next()方法可以接收参数
- 传入参数,把上一个yield返回值给覆盖了
- 第一个.next()方法其实是启动器,之前没有yield语句,因此传参无意义
function* xxfn(){ var n = 1; var v = yield n+22; console.log('aa---'+v); yield ++n; yield ++n; } var xxfn= xxfn(); console.log(xxfn.next()); //23 xxfn.next('abc'); // aa--- abc console.log(xxfn.next()); // 3