ES6 学习笔记(十一)迭代器和生成器函数
1、前言
JavaScript提供了许多的方法来获取数组或者对象中的某个元素或者属性(迭代)。从以前的for循环到之后的filter、map再到后来的for...in和for...of的迭代机制。只要具有iterator接口的都可被迭代。
2、迭代器 Iterator
2.1 含义
迭代器(iterator)为各种数据结构,提供一个统一的、简便的访问接口,简单的说,迭代可以是数组或对象的遍历方式。它使得数据结构的成员能够按某种次序排列,如上面所说,只要部署 Iterator 接口,就可以完成遍历操作。即依次处理该数据结构的所有成员。
2.2 工作过程
- 首先,创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
- 第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员
- 第二次调用指针对象的next方法,指针就指向数据结构的第二个成员,以此类推。
- 不断调用指针对象的next方法,直到它指向数据结构的结束位置
2.3 Symbol.iterator属性
2.3.1 简介
ES6 规定,默认的 Iterator 接口部署在数据结构的Symbol.iterator属性。也就是说,只要某种数据结构具有iterator接口,就是可遍历的。常见的具有这一特点的数据结构有:Array、Map、Set、String、TypedArray(类型化的数组)、函数的 arguments 对象、NodeList 对象
2.3.2 示例1:数组的iterator示例
let arr = [1, 2, 3]
let iter = arr[Symbol.iterator]()
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
运行结果:
{ value: 1, done: false }
{ value: 2, done: false }
{ value: 3, done: false }
{ value: undefined, done: true }
其中,上面的iter返回的是一个迭代器对象,由于arr数组只有3个元素,所以经过3次的next()调用之后,第四次指针指到尾部了,已经结束了,所以获取的value值为undefined。迭代已完成,所以返回done。
2.3.3 对象的Iterator
一个对象如果要具备可被for...of循环调用的 Iterator 接口,就必须在Symbol.iterator的属性上部署遍历器生成方法(原型链上的对象具有该方法也可)。
2.3.4 示例2 实现iterator接口的自定义类示例
class RangeIterator {
constructor(start, stop, step) {
this.value = start;
this.stop = stop;
this.step = step;
}
[Symbol.iterator]() {
return this;
}
next() {
let value = this.value;
if (value < this.stop) {
this.value += this.step;
return { done: false, value: value };
}
return { done: true, value: undefined };
}
}
function range(start, stop, step = 1) {
return new RangeIterator(start, stop, step);
}
for (let value of range(0, 9, 2)) {
console.log(value);
}
输出结果:
0
2
4
6
8
2.3.5 示例3 为对象添加iterator示例
// 给对象添加iterator接口
let obj = {
data: [1, 2, 3, 4, 5, 6],
[Symbol.iterator]() {
const self = this;
let index = 0;
return {
next() {
if (index < self.data.length) {
return {
value: self.data[index++],
done: false
}
} else {
return {
value: undefined,
done: true
}
}
}
}
}
}
let sum = 0
for (let d of obj) {
sum += d
}
console.log(sum);
输出结果:
21
3、生成器 Generator
3.1、含义
在前面的文章 中也提到过生成器,举个最简单的例子:
let gen = function* () {
yield 1;
yield 2;
yield 3;
}
for (let n of gen()) {
console.log(n);
}
很明显,生成器的函数的function后面有个*,函数中存在yield 关键字,在函数中,通过gen()进行函数调用并生成控制器,在这里是通过循环执行函数的。
再举个例子
let obj = {
name: "Tom",
age: 20,
*[Symbol.iterator]() {
yield this.name;
yield this.age;
}
}
console.log(obj[Symbol.iterator]().next());
console.log([...obj]);
for (let k of obj) {
console.log(k);
}
输出结果:
{ value: 'Tom', done: false }
[ 'Tom', 20 ]
Tom
20
可以看到,Generator 函数返回的遍历器对象,只有调用next方法才会遍历下一个内部状态,所以其实提供了一种可以暂停执行的函数。yield表达式就是暂停标志。
3.2 工作过程
遍历器对象的next方法的运行逻辑:
- 遇到yield表达式,就暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回的对象的value属性值。
- 下一次调用next方法时,再继续往下执行,直到遇到下一个yield表达式。
- 如果没有再遇到新的yield表达式,就一直运行到函数结束,直到return语句为止,并将return语句后面的表达式的值,作为返回的对象的value属性值。
- 如果该函数没有return语句,则返回的对象的value属性值为undefined。
3.3 Generator 函数的return方法
举个例子:
// 生成器函数
let gen = function* () {
yield 1;
yield 2;
yield 3;
return 'ok'
}
let g = gen()
console.log(g.next());
console.log(g.next());
console.log(g.next());
console.log(g.next());
console.log(g.next());
输出结果:
{ value: 1, done: false }
{ value: 2, done: false }
{ value: 3, done: false }
{ value: 'ok', done: true }
{ value: undefined, done: true }
由于在遍历到第三个next()时循环就已经结束了。再次遍历返回OK,done为true,再次遍历,由于指针已经到队列末尾,所以值为undefined。
如果for...of循环提前退出(通常是因为出错,或者有break语句),就会调用return方法。如果一个对象在完成遍历前,需要清理或释放资源,就可以部署return方法。
3.4 示例:定义类Fib,实现Fibonacci数列的获取
Fibonacci数列的后一个数等于前两个数之和
// 斐波拉契数列
class Fib {
constructor(num) {
this.num = num
}
*[Symbol.iterator]() {
let [a, b] = [0, 1]
while (true) {
[a, b] = [b, a + b]
if (a > this.num) return
yield a
}
}
}
let fibs = new Fib(100)
for (let f of fibs) {
console.log(f);
}
输出结果:
1
1
2
3
5
8
13
21
34
55
89
ES6 学习笔记(十一)迭代器和生成器函数的更多相关文章
- ES6学习笔记<二>arrow functions 箭头函数、template string、destructuring
接着上一篇的说. arrow functions 箭头函数 => 更便捷的函数声明 document.getElementById("click_1").onclick = ...
- python学习笔记四 迭代器,生成器,装饰器(基础篇)
迭代器 __iter__方法返回一个迭代器,它是具有__next__方法的对象.在调用__next__方法时,迭代器会返回它的下一个值,若__next__方法调用迭代器 没有值返回,就会引发一个Sto ...
- python3学习笔记10(迭代器和生成器)
参考http://www.runoob.com/python3/python3-iterator-generator.html 迭代器 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束 ...
- Python学习笔记010_迭代器_生成器
迭代器 迭代就类似于循环,每次重复的过程被称为迭代的过程,每次迭代的结果将被用来作为下一次迭代的初始值,提供迭代方法的容器被称为迭代器. 常见的迭代器有 (列表.元祖.字典.字符串.文件 等),通常 ...
- python 3.x 学习笔记6 ( 迭代器 and 生成器 )
1.迭代器(Iterator): 可以被next()函数调用并不断返回下一个值的对象,成为迭代器:Iterator 可以直接用于for 循环的对象统称为可迭代对象:Iterable 迭代,顾名思 ...
- ES6学习笔记(四)—— async 函数
await 是 async wait 的简写, 是 generator 函数的语法糖. async 函数的特点: async 声明一个方法是异步的,await 则等待这个异步方法执行的完成 async ...
- ES6学习笔记十一:编程风格技巧
一:用let取代var 二:静态字符串一律使用单引号或反引号,不使用双引号.动态字符串(模版字符串)使用反引号. 三:解构赋值: 使用数组对变量赋值时,优先使用解构赋值: 函数的参数如果是对象的成员, ...
- ES6学习笔记(2)- 箭头函数
1. 箭头函数声明 箭头函数的声明方式示例: 1 const printValue = (condition) => { 2 let testValue = 55; 3 if (conditio ...
- ES6学习笔记<三> 生成器函数与yield
为什么要把这个内容拿出来单独做一篇学习笔记? 生成器函数比较重要,相对不是很容易理解,单独做一篇笔记详细聊一聊生成器函数. 标题为什么是生成器函数与yield? 生成器函数类似其他服务器端语音中的接口 ...
- ES6学习笔记<五> Module的操作——import、export、as
import export 这两个家伙对应的就是es6自己的 module功能. 我们之前写的Javascript一直都没有模块化的体系,无法将一个庞大的js工程拆分成一个个功能相对独立但相互依赖的小 ...
随机推荐
- 【ARK UI】HarmonyOS 从相册选择图片并显示到Image组件上
参考资料 [Harmony OS][ARK UI]ETS 上下文基本操作 [Harmony OS][ARK UI]ets使用startAbility或startAbilityForResult方式 ...
- 「雅礼集训 2017 Day2」线段游戏(线段树懒标记“启发式下传”,李超树)
题面 题解 加入一条线段,可以把它转化为在[L,R]区间内加一条线 y=ax+b (如果原线段与y轴平行,就相当于在{x1}处加一条线 y=max(y1,y2)) 我们可以把它加到线段树上,线段树上每 ...
- openstack中Cinder组件简解
一,Cinder组件介绍 概念 cinder组件作用: 块存储服务,为运行实例提供稳定的数据块存储服务 块存储服务,提供对 volume 从创建到删除整个生命周期的管理 二,常用操作 1.Volume ...
- Kingbase V8R6集群安装部署案例---脚本在线一键缩容
案例说明: KingbaseES V8R6支持图形化方式在线缩容,但是在一些生产环境,在服务器不支持图形化界面的情况下 ,只能通过脚本命令行的方式执行集群的部署或在线缩容. Tips: Kingb ...
- 【读书笔记】C#高级编程 第三章 对象和类型
(一)类和结构 类和结构实际上都是创建对象的模板,每个对象都包含数据,并提供了处理和访问数据的方法. 类和结构的区别:内存中的存储方式.访问方式(类是存储在堆上的引用类型,结构是存储在栈的值类型)和它 ...
- filebeat测试output连通性
在默认的情况下,直接运行filebeat的话,它选择的默认的配置文件是当前目录下的filebeat.yml文件. filebeat.yml文件内容 filebeat.inputs: - type: l ...
- OSF--网络类型
ABR:区域边界路由器ASBR:自治区域系统边界路由器区域部署原则: 存在vlink本地网络一定是有问题的.他只是作为一种过度技术,在vlink里无法实现认证! 配置: [r2-ospf-a ...
- Jhipster自动生成实体类等文件
官网:https://www.jhipster.tech/cn/ 准备工作 安装node(npm) 准备jdl文件 安装Jhipster:npm install -g generator-jhipst ...
- [题解] Codeforces 1548 C The Three Little Pigs 组合数学,生成函数
题目 首先令\(x=i\)时的答案为\(f_i\) ,令\(f_i\)对应的普通生成函数为\(F(x)\). 很容易发现\(F(x)=\sum_{i=0}^n (1+x)^{3i}\),sigma是在 ...
- 华为网关交换机开启DHCP server服务
华为网关交换机可以配置基于全局地址池的DHCP服务器,也可以配置基于接口地址池的DHCP服务器,本人比较倾向于配置基于接口地址池的DHCP服务器,因此在这里只介绍后者. 第一步:开启DHCP功能 [S ...