Generator 函数学习笔记
- // 使用 function* 定义一个 generator 函数
- function* helloWorldGenerator() {
- yield 'hello'; // yield 关键字作为暂停的点
- yield 'world';
- return 'ending';
- }
- var hw = helloWorldGenerator(); // 执行 generator 函数,返回一个遍历器对象。而这时,这个函数内的代码并不会执行。
- // 调用遍历器对象的 next 方法,执行函数内的代码,执行到下一个 yield 的位置,并暂停执行
- hw.next()
- // { value: 'hello', done: false } value 是 yield 后面跟的表达式的值,done 是 genertator 函数结束状态
- // 再次调用 next,执行到下一个 yield 位置
- hw.next()
- // { value: 'world', done: false }
- // 执行结束,value 值为 return 的值,没有 return 则为 undefined(函数没 return 返回 undefined),done 变为 true
- hw.next()
- // { value: 'ending', done: true }
- // 还可以无限次调用 next,但是都返回相同的对象
- hw.next()
- // { value: undefined, done: true }
yield 不能用在普通函数中:
- var flat = function* (a) {
- // forEach 方法是个普通函数,在里面使用了 yield 会报错。解决方法是改为 for 循环
- a.forEach(function (item) {
- if (typeof item !== 'number') {
- yield* flat(item);
- } else {
- yield item;
- }
- }
- };
yield
语句如果用在一个表达式之中,必须放在圆括号里面。
- console.log('Hello' + yield); // SyntaxError
- console.log('Hello' + yield 123); // SyntaxError
- console.log('Hello' + (yield)); // OK
- console.log('Hello' + (yield 123)); // OK
next方法的参数
- function* foo(x) {
- var y = 2 * (yield (x + 1)); // yield 语句在表达式中,需要将 yield 语句括起来,否则报错
- var z = yield (y / 3);
- return (x + y + z);
- }
- var a = foo(5);
- a.next() // Object{value:6, done:false}
- a.next() // Object{value:NaN, done:false}
- a.next() // Object{value:NaN, done:true}
- var b = foo(5);
- b.next() // { value:6, done:false } 调用第一次 next 开始执行,得到第一个 yield 的返回值 6。由于 next 参数为上一个 yield 语句的值,所以第一个 next 传入参数没有意义
- b.next(12) // { value:8, done:false } 调用 next 方法时注入了数据,作为上一个 yield 语句的值,得到 var y = 2 * 12
- b.next(13) // { value:42, done:true } 得到 var z = 13
for...of循环
for...of
循环可以自动遍历Generator函数时生成的Iterator
对象,且此时不再需要调用next
方法。
- function *foo() {
- yield 1;
- yield 2;
- yield 3;
- yield 4;
- yield 5;
- return 6;
- }
- for (let v of foo()) {
- console.log(v);
- }
- // 1 2 3 4 5 这里需要注意,一旦
next
方法的返回对象的done
属性为true
,for...of
循环就会中止,且不包含该返回对象,所以上面代码的return
语句返回的6,不包括在for...of
循环之中。
原生的JavaScript对象没有遍历接口,无法使用for...of
循环,通过Generator函数为它加上这个接口,就可以用了。
- // 第一种方法
- function* objectEntries(obj) {
- let propKeys = Reflect.ownKeys(obj);
- for (let propKey of propKeys) {
- yield [propKey, obj[propKey]];
- }
- }
- let jane = { first: 'Jane', last: 'Doe' };
- for (let [key, value] of objectEntries(jane)) {
- console.log(`${key}: ${value}`);
- }
- // 第二种方法
- function* objectEntries() {
- let propKeys = Object.keys(this);
- for (let propKey of propKeys) {
- yield [propKey, this[propKey]];
- }
- }
- let jane = { first: 'Jane', last: 'Doe' };
- jane[Symbol.iterator] = objectEntries;
- for (let [key, value] of jane) {
- console.log(`${key}: ${value}`);
- }
Generator.prototype.throw()
Generator函数返回的遍历器对象,都有一个throw
方法,可以在函数体外抛出错误,然后在Generator函数体内捕获。
- var g = function* () {
// 使用 try...catch... 进行异常捕获
try {- yield;
- } catch (e) {
- console.log('内部捕获', e);
- }
- };
- var i = g();
- i.next();
- try {
- i.throw('a'); // 这里使用 throw 方法抛出的错误,会由 generator 函数内的 catch 处理
- i.throw('b'); // generator 内的 catch 已经执行过了,就不会再被 generator 的 catch 捕获了,由外部的 catch 捕获
- } catch (e) {
- console.log('外部捕获', e);
- }
- // 内部捕获 a
- // 外部捕获 b
如果Generator函数内部没有部署try...catch
代码块,那么throw
方法抛出的错误,将被外部try...catch
代码块捕获。
如果Generator函数内部和外部,都没有部署try...catch
代码块,那么程序将报错,直接中断执行。
throw
方法被捕获以后,会附带执行下一条yield
语句。也就是说,会附带执行一次next
方法。
- var gen = function* gen(){
- try {
- yield console.log('a');
- } catch (e) {
- // ...
- }
- yield console.log('b'); // throw 方法会附带执行 next,从而执行到这个 yield 位置
- yield console.log('c');
- }
- var g = gen();
- g.next() // a
- g.throw() // b
- g.next() // c
Generator.prototype.return()
Generator函数返回的遍历器对象,还有一个return
方法,可以返回给定的值,并且终结遍历Generator函数。
- function* gen() {
- yield 1;
- yield 2;
- yield 3;
- }
- var g = gen();
- g.next() // { value: 1, done: false }
- g.return('foo') // { value: "foo", done: true } value 值变成了 return 的参数
- g.next() // { value: undefined, done: true } return 方法 导致 generator 函数结束,所以 value 为 undefined
yield*语句
- function* foo() {
- yield 'a';
- yield 'b';
- }
- function* bar() {
- yield 'x';
- // foo(); 如果只是单纯的执行 foo() 函数,只是得到一个遍历器对象,并不会产生什么效果。
- yield* foo(); // 使用了 yield* 语句,在遍历的时候才会遍历这个 generator 函数内部的 generator 函数。
- yield 'y';
- }
- for (let v of bar()){
- console.log(v);
- }
- // "x"
- // "a"
- // "b"
- // "y"
- function* gen(){
- yield* ["a", "b", "c"]; // 数组、字符串等,带有 iterator 接口的,都可以被 yield* 遍历
- }
- gen().next() // { value:"a", done:false }
Generator与状态机
- var clock = function*() {
- while (true) {
- console.log('Tick!'); // 执行状态1代码
- yield;
- console.log('Tock!'); // 执行状态2代码
- yield;
- }
- };
每次调用 next() 就可以在两种状态间切换执行,而不需要使用一个布尔变量来做判断
Generator 函数学习笔记的更多相关文章
- C++学习基础十六-- 函数学习笔记
C++ Primer 第七章-函数学习笔记 一步一个脚印.循序渐进的学习. 一.参数传递 每次调用函数时,都会重新创建函数所有的形参,此时所传递的实参将会初始化对应的形参. 「如果形参是非引用类型,则 ...
- async 函数学习笔记
async函数就是Generator函数的语法糖. var fs = require('fs'); var readFile = function (fileName) { return new Pr ...
- async 函数--学习笔记一
含义: ES2017 标准引入了 async 函数,使得异步操作变得更加方便.async 函数是什么?一句话,它就是 Generator 函数的语法糖. 前文有一个 Generator 函数,依次读取 ...
- async函数学习笔记
含义 async函数是什么?一句话,它就是Generator函数的语法糖. const fs = require('fs') const readFile = function(fileName){ ...
- contiki-main.c 中的process系列函数学习笔记 <contiki学习笔记之六>
说明:本文依然依赖于 contiki/platform/native/contiki-main.c 文件. ---------------------------------------------- ...
- Swift2.0 函数学习笔记
最近又有点忙,忙着找工作,忙着适应这个新环境.现在好了,上班两周周了,也适应过来了,又有时间安安静静的就行我们前面的学习了.今天这篇笔记,记录的就是函数的使用.下面这些代码基本上是理清楚了函数的额使用 ...
- MYSQL存储过程和函数学习笔记
学至Tarena金牌讲师,金色晨曦科技公司技术总监沙利穆课程笔记的综合. 1. 什么是存储过程和函数 将SQL语句放入一个集合里,然后直接调用存储过程和函数来执行已经定义好的SQL语句,通过存储过程和 ...
- loss函数学习笔记
一直对机器学习里的loss函数不太懂,这里做点笔记. 符号表示的含义,主要根据Andrew Ng的课程来的,\(m\)个样本,第\(i\)个样本为\(\vec x^{(i)}\),对应ground t ...
- jQuery 取消事件冒泡 阻止后续内容执行 闭包函数 (学习笔记)
1.取消事件冒泡 <title>取消事件冒泡</title> <style> div { border:solid 1px black; } </style& ...
随机推荐
- GIS服务器需求分析
一. 需求概要 1 边界 核心职责 接收并存储外部各方系统GPS数据 GPS数据实时分发, 轨迹检索 2 流程 GIS客户端向GIS服务器订购 GIS客户端向GIS服务器订购号码(仅有号码这一项业 ...
- iOS核心动画学习整理
最近利用业余时间终于把iOS核心动画高级技巧(https://zsisme.gitbooks.io/ios-/content/chapter1/the-layer-tree.html)看完,对应其中一 ...
- 关于Dagger 2 的使用方式
什么是Dagger2 Dagger是为Android和Java平台提供的一个完全静态的,在编译时进行依赖注入的框架,原来是由Square公司维护,现在由Google维护. 我们知道Dagger是一个依 ...
- iOS开发之UITapGestureRecognizer单双击
转自手势开发 IOS开发之手势——UIGestureRecognizer 共存 在 iPhone 或 iPad 的开发中,除了用 touchesBegan / touchesMoved / touch ...
- 从零搭建mongo分片集群的简洁方法
一.目录 1.mongo路径,config数据路径,shard数据路径
- 使用 GPG 对数据进行加密解密签名
一:使用 GPG 对数据进行加密解密签名 基本的工具使用 1. GPG 是GNUPG 免费开源的gpg加密工具,和同pgp兼容,pgp收费. 2. 在mac上使用https://gpgtools.or ...
- linux下使用shell查看apache IP访问量
1.查看TCP连接状态 netstat -nat |awk '{print $6}'|sort|uniq -c|sort -rn netstat -n | awk '/^tcp/ {++S[$NF]} ...
- C#微信公众号接口开发实例-高级接口-申请带参数的二维码
最近公司涉及到微信绑定用户,做了高级接口-申请带参数的二维码,总结了下微信开发接口.微信接口开发都是除了消息用的xml 回复基本上都是用json的形式传递信息(post/get),开发的方法基本都是一 ...
- vm10虚拟机安装Mac OS X10.10教程[转]
update:http://www.sysprobs.com/vmware-workstation-8-0-8-0-1-unlocker-to-run-mac-os-x-guest-in-window ...
- 【转】nginx+tomcat+memcached (msm)实现 session同步复制
出现session不同步时,请放到content.xml中,实际验证有效: tomcat + memcached + nginx 实现session共享 这里重点强调如何实现linux服务器上 服务器 ...