JavaScript学习笔记(十三)——生成器(generator)
在学习廖雪峰前辈的JavaScript教程中,遇到了一些需要注意的点,因此作为学习笔记列出来,提醒自己注意!
如果大家有需要,欢迎访问前辈的博客https://www.liaoxuefeng.com/学习。
generator(生成器)是ES6标准引入的新的数据类型。一个generator看上去像一个函数,但可以返回多次。
我们先看一下函数的概念:
一个函数是一段完整的代码,调用一个函数就是传入参数,然后返回结果。
function foo(x) {
return x + x;
}
var r = foo(1); // 调用foo函数
在函数执行过程中,如果没有遇到 return 语句,控制权无法交回被调用的代码。(函数末尾如果没有return,就是隐含的return undefined;)
generator定义
function* foo(x) {
yield x + 1;
yield x + 2;
return x + 3;
}
generator与函数的区别
generator由 function* 定义(注意多出的*号),并且,除了 return 语句,还可以用 yield 返回多次。
举个例子就容易理解了:
著名的斐波拉切数列,它是由0,1开头:
0 1 1 2 3 5 8 13 21 34 ...
要编写一个产生斐波那契数列的函数,可以这么写:
function fib(max) {
var
t,
a = 0,
b = 1,
arr = [0, 1];
while (arr.length < max) {
[a, b] = [b, a + b];
arr.push(b);
}
return arr;
}
// 测试:
fib(5); // [0, 1, 1, 2, 3]
fib(10); // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
函数只能返回一次,所以必须返回一个Array。
但是,如果换成generator,就可以一次返回一个数,不断返回多次。用generator改写如下:
'use strict'
function* fib(max) {
var
t,
a = 0,
b = 1,
n = 0;
while (n < max) {
yield a;
[a, b] = [b, a + b];
n ++;
}
return;
}
直接调用:
fib(5); // fib {[[GeneratorStatus]]: "suspended", [[GeneratorReceiver]]: Window}
我们发现,直接调用一个generator和调用函数不一样, fib(5) 仅仅是创建了一个generator对象,还没有去执行它。
调用generator对象有两个方法:
一是不断地调用generator对象的 next() 方法:
var f = fib(5);
f.next(); // {value: 0, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 2, done: false}
f.next(); // {value: 3, done: false}
f.next(); // {value: undefined, done: true}
next() 方法会执行generator的代码,然后,每次遇到 yield x; 就返回一个对象 {value: x, done: true/false} ,然后“暂停”。返回的 value 就是 yield 的返回值, done 表示这个generator是否已经执行结束了。如果 done 为 true ,则 value 就是 return 的返回值。
当执行到 done 为 true 时,这个generator对象就已经全部执行完毕,不要再继续调用 next() 了。
二是直接用 for......of 循环迭代generator对象,这种方式不需要我们自己加判断 done :
for (var x of fib(10)) {
console.log(x); // 依次输出0, 1, 1, 2, 3, ...
}
generator优点
1.正是由于generator在执行过程中能多次返回,所以它看上去像一个可以记住执行状态的函数,利用这一点,可以通过写一个generator来实现需要用面向对象才能实现的功能。
比如,用一个对象来保存状态,我们一般是用对象的属性来保存。这样很繁琐:
var fib = {
a: 0,
b: 1,
n: 0,
max: 5,
next: function () {
var
r = this.a,
t = this.a + this.b;
this.a = this.b;
this.b = t;
if (this.n < this.max) {
this.n ++;
return r;
} else {
return undefined;
}
}
};
2.generator还有另一个巨大的好处,就是把异步回调代码变成“同步”代码。
没有generator时,用AJAX时需要这么写代码:
ajax('http://url-1', data1, function (err, result) {
if (err) {
return handle(err);
}
ajax('http://url-2', data2, function (err, result) {
if (err) {
return handle(err);
}
ajax('http://url-3', data3, function (err, result) {
if (err) {
return handle(err);
}
return success(result);
});
});
});
回调越多,代码越难看。
通过使用generator时,可以这么写:
try {
r1 = yield ajax('http://url-1', data1);
r2 = yield ajax('http://url-2', data2);
r3 = yield ajax('http://url-3', data3);
success(r3);
}
catch (err) {
handle(err);
}
看上去是同步的代码,实际上是异步的代码。
JavaScript学习笔记(十三)——生成器(generator)的更多相关文章
- Python学习笔记014——生成器Generator
1 生成器定义 在Python中,一边循环一边计算的机制,称之为生成器(generator). 生成器是一个迭代器. 含有yield语句的函数是生成器函数,该函数被调用时返回一个生成器对象(yield ...
- javascript学习笔记(四) Number 数字类型
数字格式化方法toFixed().toExponential().toPrecision(),三个方法都四舍五入 toFixed() 方法指定小数位个数 toExponential() 方法 用科学 ...
- ES6学习笔记<三> 生成器函数与yield
为什么要把这个内容拿出来单独做一篇学习笔记? 生成器函数比较重要,相对不是很容易理解,单独做一篇笔记详细聊一聊生成器函数. 标题为什么是生成器函数与yield? 生成器函数类似其他服务器端语音中的接口 ...
- JavaScript学习笔记[0]
JavaScript学习笔记[0] 使用的是廖雪峰JavaScript教程. 数据类型 Number 表示数字,不区分浮点整形. === 比较时不转化数据类型. == 反之. NaN与任何值都不想等, ...
- python3.4学习笔记(十三) 网络爬虫实例代码,使用pyspider抓取多牛投资吧里面的文章信息,抓取政府网新闻内容
python3.4学习笔记(十三) 网络爬虫实例代码,使用pyspider抓取多牛投资吧里面的文章信息PySpider:一个国人编写的强大的网络爬虫系统并带有强大的WebUI,采用Python语言编写 ...
- Java程序猿的JavaScript学习笔记(汇总文件夹)
最终完结了,历时半个月. 内容包含: JavaScript面向对象特性分析,JavaScript高手必经之路. jQuery源代码级解析. jQuery EasyUI源代码级解析. Java程序猿的J ...
- Java程序猿的JavaScript学习笔记(8——jQuery选择器)
计划按例如以下顺序完毕这篇笔记: Java程序猿的JavaScript学习笔记(1--理念) Java程序猿的JavaScript学习笔记(2--属性复制和继承) Java程序猿的JavaScript ...
- Java程序猿JavaScript学习笔记(2——复制和继承财产)
计划和完成在这个例子中,音符的以下序列: Java程序猿的JavaScript学习笔记(1--理念) Java程序猿的JavaScript学习笔记(2--属性复制和继承) Java程序猿的JavaSc ...
- java之jvm学习笔记十三(jvm基本结构)
java之jvm学习笔记十三(jvm基本结构) 这一节,主要来学习jvm的基本结构,也就是概述.说是概述,内容很多,而且概念量也很大,不过关于概念方面,你不用担心,我完全有信心,让概念在你的脑子里变成 ...
- Java程序猿的JavaScript学习笔记(3——this/call/apply)
计划按例如以下顺序完毕这篇笔记: Java程序猿的JavaScript学习笔记(1--理念) Java程序猿的JavaScript学习笔记(2--属性复制和继承) Java程序猿的JavaScript ...
随机推荐
- flume自定义Source(taildirSource),自定义Sink(数据库),开发完整步骤
一.flume简单了解推荐网站(简介包括简单案例部署): http://www.aboutyun.com/thread-8917-1-1.html 二.我的需求是实现从ftp目录下采集数据,目录下文件 ...
- 深入浅出:JavaScript作用域链
1. 什么是作用域 任何程序设计语言都有作用域的概念,简单的说,作用域就是变量的作用范围. 2. 变量的分类和变量作用域的分类 在JavaScript中,变量分为全局变量和局部变量,与此相对应的,变量 ...
- Python学习笔记(六)
Python学习笔记(六) Ubuntu重置root密码 Ubuntu 16.4 目录结构 Ubuntu 命令讲解 1. Ubuntu重置root密码 启动系统,显示GRUB选择菜单(如果默认系统启动 ...
- vue-cli中如何引入jquery
前言 虽然vue不推荐直接操作DOM,而且也提供了操作DOM的方式.但是在某些时候还是要用到jquery(囧),那么如何在使用vue-cli的时候引入jquery呢? 安装 国内镜像 cnpm 安装 ...
- LINUX 笔记-命令执行顺序 && ,||
&& 格式:命令1 && 命令2 说明:命令1返回真(即返回0,成功被执行)后,命令2才能够被执行 例:/apps/bin目录将会被移到/apps/dev/bin目录下 ...
- Java基础(00)
Java发展史 Java之父:詹姆斯.高斯林(James Gosling). SUN(Stanford University Network 斯坦福大学网络公司)产物. 1995年5月23日,java ...
- Linux系统LVM基本使用
一.关于LVM的几个概念 1. LVM:逻辑卷管理器,是建立在物理存储设备上的一个抽象层,允许你生成逻辑存储卷, 与硬件相关的存储设置被其隐藏,你不用停止应用或卸载文件系统来调整卷大小 或迁移数据,可 ...
- Myeclipse 2014破解教程
现在很多java编程软件人士大都使用MyEclipse,这软件的强大之处我就不说了,我说下安装步骤与破解步骤,若无JDK则先安装再配置环境变量,这个我就不讲了 工具/原料 MyEclipse安装包 ...
- windows 上rsync客户端使用方法
1.1 获取 windows上实现rsync的软件(cwRsync) cwRsync是Windows 客户端GUI的一个包含Rsync的包装.您可以使用cwRsync快速远程文件备份和同步. 1.1. ...
- Windows下caffe的python接口配置
主要是因为,发现很多代码是用python编写的,在这里使用的python安装包是anaconda2. 对应下载地址为: https://www.continuum.io/downloads/ 安装py ...