JavaScript之生成器_动力节点Java学院整理


Posted in Javascript onJune 30, 2017

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返回多次。

大多数同学立刻就晕了,generator就是能够返回多次的“函数”?返回多次有啥用?

还是举个栗子吧。

我们以一个著名的斐波那契数列为例,它由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) {
  t = a + b;
  a = b;
  b = t;
  arr.push(t);
 }
 return arr;
}

// 测试:
fib(5); // [0, 1, 1, 2, 3]
fib(10); // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

函数只能返回一次,所以必须返回一个Array。但是,如果换成generator,就可以一次返回一个数,不断返回多次。用generator改写如下:

function* fib(max) {
 var
  t,
  a = 0,
  b = 1,
  n = 1;
 while (n < max) {
  yield a;
  t = a + b;
  a = b;
  b = t;
  n ++;
 }
 return a;
}

直接调用试试:

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: true}

next()方法会执行generator的代码,然后,每次遇到yield x;就返回一个对象{value: x, done: true/false},然后“暂停”。返回的value就是yield的返回值,done表示这个generator是否已经执行结束了。如果donetrue,则value就是return的返回值。

当执行到donetrue时,这个generator对象就已经全部执行完毕,不要再继续调用next()了。

第二个方法是直接用for ... of循环迭代generator对象,这种方式不需要我们自己判断done

for (var x of fib(5)) {
 console.log(x); // 依次输出0, 1, 1, 2, 3
}

generator和普通函数相比,有什么用?

因为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;
  }
 }
};

用对象的属性来保存状态,相当繁琐。

generator还有另一个巨大的好处,就是把异步回调代码变成“同步”代码。这个好处要等到后面学了AJAX以后才能体会到。

没有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的美好时代,用AJAX时可以这么写:

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);
}

看上去是同步的代码,实际执行是异步的。

练习

要生成一个自增的ID,可以编写一个next_id()函数

Javascript 相关文章推荐
jquery数组封装使用方法分享(jquery数组遍历)
Mar 25 Javascript
Egret引擎开发指南之运行项目
Sep 03 Javascript
jQuery过滤选择器经典应用
Aug 18 Javascript
AngularJS入门教程之模块化操作用法示例
Nov 02 Javascript
基于iscroll.js实现下拉刷新和上拉加载效果
Nov 28 Javascript
js实现炫酷的左右轮播图
Jan 18 Javascript
JavaScript基础之AJAX简单的小demo
Jan 29 Javascript
JS函数节流和防抖之间的区分和实现详解
Jan 11 Javascript
vue引入静态js文件的方法
Jun 20 Javascript
vue 实现setInterval 创建和销毁实例
Jul 21 Javascript
详解为什么Vue中的v-if和v-for不建议一起用
Jan 13 Vue.js
详解vite+ts快速搭建vue3项目以及介绍相关特性
Feb 25 Vue.js
详解vue组件通信的三种方式
Jun 30 #Javascript
JavaScript实现瀑布流图片效果
Jun 30 #Javascript
十大 Node.js 的 Web 框架(快速提升工作效率)
Jun 30 #Javascript
vue.js移动端tab组件的封装实践实例
Jun 30 #Javascript
jQuery表单设置值的方法
Jun 30 #jQuery
JavaScript注册时密码强度校验代码
Jun 30 #Javascript
Bootstrap Table从零开始
Jun 30 #Javascript
You might like
php提取字符串中网站url地址的方法
2014/12/03 PHP
PHP+jquery+ajax实现即时聊天功能实例
2014/12/23 PHP
微信支付开发动态链接Native支付
2016/07/12 PHP
php使用curl下载指定大小的文件实例代码
2017/09/30 PHP
2020最新版 PhpStudy V8.1版本下载安装使用详解
2020/10/30 PHP
SUN的《AJAX与J2EE》全文译了
2007/02/23 Javascript
js,jQuery 排序的实现代码,网页标签排序的实现,标签排序
2011/04/27 Javascript
Jquery实现图片放大镜效果的思路及代码(自写)
2013/10/18 Javascript
父页面显示遮罩层弹出半透明状态的dialog
2014/03/04 Javascript
Node.js 服务器端应用开发框架 -- Hapi.js
2014/07/29 Javascript
javascript 兼容各个浏览器的事件
2015/02/04 Javascript
jquery处理页面弹出层查询数据等待操作实例
2015/03/25 Javascript
jquery+html5时钟特效代码分享(可设置闹钟并且语音提醒)
2020/03/30 Javascript
JS实现的另类手风琴效果网页内容切换代码
2015/09/08 Javascript
Javascript中常见的逻辑题和解决方法
2016/09/17 Javascript
jquery获取easyui日期控件的值实现方法
2016/11/09 Javascript
Javascript的console['']常用输入方法汇总
2018/04/26 Javascript
vue项目中公用footer组件底部位置的适配问题
2018/05/10 Javascript
详解vue的双向绑定原理及实现
2019/05/05 Javascript
layui富文本编辑器前端无法取值的解决方法
2019/09/18 Javascript
jquery实现聊天机器人
2020/02/08 jQuery
vue中的过滤器及其时间格式化问题
2020/04/09 Javascript
vue中touch和click共存的解决方式
2020/07/28 Javascript
python模拟enum枚举类型的方法小结
2015/04/30 Python
tensorflow使用freeze_graph.py将ckpt转为pb文件的方法
2020/04/22 Python
浅谈matplotlib 绘制梯度下降求解过程
2020/07/12 Python
利用Python实现学生信息管理系统的完整实例
2020/12/30 Python
纯css3无js实现的Android Logo(有简单动画)
2013/01/21 HTML / CSS
历史专业个人求职信范文
2013/12/07 职场文书
党员一句话承诺大全
2014/03/28 职场文书
工程部岗位职责范本
2015/04/11 职场文书
2015少先队大队辅导员工作总结
2015/07/24 职场文书
优秀创业计划书分享
2019/07/19 职场文书
亲情作文之母爱
2019/09/25 职场文书
vue3.0 数字翻牌组件的使用方法详解
2022/04/20 Vue.js
Python使用openpyxl模块处理Excel文件
2022/06/05 Python