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 相关文章推荐
Javascript中获取出错代码所在文件及行数的代码
Sep 23 Javascript
js URL参数的拼接方法比较
Feb 15 Javascript
jQuery中复合属性选择器用法实例
Dec 31 Javascript
JS限制文本框只能输入数字和字母方法
Feb 28 Javascript
Node.js中的process.nextTick使用实例
Jun 25 Javascript
将html页面保存成图片,图片写入pdf的实现方法(推荐)
Sep 17 Javascript
jQuery EasyUI tree 使用拖拽时遇到的错误小结
Oct 10 Javascript
JavaScript获取当前时间向前推三个月的方法示例
Feb 04 Javascript
基于react框架使用的一些细节要点的思考
May 31 Javascript
微信小程序 行的删除和增加操作实现详解
Sep 29 Javascript
在Koa.js中实现文件上传的接口功能
Oct 08 Javascript
JavaScript事件循环及宏任务微任务原理解析
Sep 02 Javascript
详解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 文件上传功能实现代码
2009/06/24 PHP
PHP文件去掉PHP注释空格的函数分析(PHP代码压缩)
2013/07/02 PHP
PHP的RSA加密解密方法以及开发接口使用
2018/02/11 PHP
PHP手机短信验证码实现流程详解
2018/05/17 PHP
Centos7 Yum安装PHP7.2流程教程详解
2019/07/02 PHP
Yii框架学习笔记之应用组件操作示例
2019/11/13 PHP
js 父窗口控制子窗口的行为-打开,关闭,重定位,回复
2010/04/20 Javascript
firebug的一个有趣现象介绍
2011/11/30 Javascript
JavaScript验证图片类型(扩展名)的函数分享
2014/05/05 Javascript
JS函数的定义与调用方法推荐
2016/05/12 Javascript
layer弹出层框架alert与msg详解
2017/03/14 Javascript
Python生成随机密码
2015/03/10 Python
Python使用openpyxl读写excel文件的方法
2017/06/30 Python
Python基于property实现类的特性操作示例
2018/06/15 Python
python3.7.0的安装步骤
2018/08/27 Python
Python面向对象之接口、抽象类与多态详解
2018/08/27 Python
关于Python核心框架tornado的异步协程的2种方法详解
2019/08/28 Python
python模块hashlib(加密服务)知识点讲解
2019/11/25 Python
Python爬取新型冠状病毒“谣言”新闻进行数据分析
2020/02/16 Python
详解用Pytest+Allure生成漂亮的HTML图形化测试报告
2020/03/31 Python
PyCharm 在Windows的有用快捷键详解
2020/04/07 Python
用于ETL的Python数据转换工具详解
2020/07/21 Python
Python jieba结巴分词原理及用法解析
2020/11/05 Python
阿拉伯世界最大的电子商务网站:Souq沙特阿拉伯
2016/10/28 全球购物
护士辞职信模板
2014/01/20 职场文书
爷爷追悼会答谢词
2014/01/24 职场文书
国庆节文艺活动方案
2014/02/03 职场文书
相亲大会策划方案
2014/06/05 职场文书
机关中层领导干部群众路线教育实践活动个人对照检查材料
2014/09/24 职场文书
2014村党支部书记党建工作汇报材料
2014/11/02 职场文书
事业单位考察材料范文
2014/12/25 职场文书
财务出纳岗位职责
2015/03/31 职场文书
2015年安全生产管理工作总结
2015/05/25 职场文书
天河观后感
2015/06/11 职场文书
出生证明格式
2015/06/15 职场文书
死磕 java同步系列之synchronized解析
2021/06/28 Java/Android