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基础框架浅入剖析
Dec 27 Javascript
javascript中with()方法的语法格式及使用
Aug 04 Javascript
使用jQuery jqPlot插件绘制柱状图
Dec 18 Javascript
jQuery.deferred对象使用详解
Mar 18 Javascript
Angular2开发——组件规划篇
Mar 28 Javascript
angular 基于ng-messages的表单验证实例
May 04 Javascript
javascript高级模块化require.js的具体使用方法
Oct 31 Javascript
vue interceptor 使用教程实例详解
Sep 13 Javascript
js实现点击展开隐藏效果(实例代码)
Sep 28 Javascript
React 路由懒加载的几种实现方案
Oct 23 Javascript
微信小程序生成海报分享朋友圈的实现方法
May 06 Javascript
使用js获取身份证年龄的示例代码
Dec 11 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+mysql实现无限级分类 | 树型显示分类关系
2006/11/19 PHP
非常经典的PHP文件上传类分享
2016/05/15 PHP
PHP入门教程之面向对象基本概念实例分析
2016/09/11 PHP
js实现幻灯片播放图片示例代码
2013/11/07 Javascript
刷新页面的几种方法小结(JS,ASP.NET)
2014/01/07 Javascript
九种原生js动画效果
2015/11/11 Javascript
jQuery实现的省市县三级联动菜单效果完整实例
2016/08/01 Javascript
AngularJS下对数组的对比分析
2016/08/24 Javascript
js document.getElementsByClassName的使用介绍与自定义函数
2016/11/25 Javascript
基于jquery二维码生成插件qrcode
2017/01/07 Javascript
js实现模糊匹配功能
2017/02/15 Javascript
jQuery实现字符串全部替换的方法【推荐】
2017/03/09 Javascript
基于JS实现仿京东搜索栏随滑动透明度渐变效果
2017/07/10 Javascript
vue实现消息的无缝滚动效果的示例代码
2017/12/05 Javascript
jQuery+datatables插件实现ajax加载数据与增删改查功能示例
2018/04/17 jQuery
React组件内事件传参实现tab切换的示例代码
2018/07/04 Javascript
angular4强制刷新视图的方法
2018/10/09 Javascript
Vue Cli3 创建项目的方法步骤
2018/10/15 Javascript
JavaScript对象拷贝与赋值操作实例分析
2018/12/10 Javascript
动态内存分配导致影响Javascript性能的问题
2018/12/18 Javascript
javascript移动端 电子书 翻页效果实现代码
2019/09/07 Javascript
vue element-ui实现input输入框金额数字添加千分位
2019/12/29 Javascript
JS实现音乐导航特效
2020/01/06 Javascript
Python实现的十进制小数与二进制小数相互转换功能
2017/10/12 Python
对pandas中Series的map函数详解
2018/07/25 Python
python 应用之Pycharm 新建模板默认添加编码格式-作者-时间等信息【推荐】
2019/06/17 Python
详解Python中打乱列表顺序random.shuffle()的使用方法
2019/11/11 Python
用python爬虫批量下载pdf的实现
2020/12/01 Python
土耳其时尚潮流在线购物网站:Trendyol
2017/10/10 全球购物
YesBabyOnline美国:全球性的在线婚纱礼服工厂
2018/05/05 全球购物
成人大专生实习期的自我评价
2013/10/02 职场文书
先进个人事迹材料
2014/01/25 职场文书
缅怀革命先烈演讲稿
2014/05/14 职场文书
专题组织生活会思想汇报
2014/10/01 职场文书
会计实训报告范文
2014/11/04 职场文书
律师函格式范本
2015/05/27 职场文书