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 相关文章推荐
一个简单的js鼠标划过切换效果
Jun 30 Javascript
JavaScript判断窗口是否最小化的代码(跨浏览器)
Aug 01 Javascript
最短的IE判断代码
Mar 13 Javascript
一个简单的网站访问JS计数器 刷新1次加1次访问
Sep 20 Javascript
文本框倒叙输入让输入框的焦点始终在最开始的位置
Sep 01 Javascript
jQuery ui实现动感的圆角渐变网站导航菜单效果代码
Aug 26 Javascript
apply和call方法定义及apply和call方法的区别
Nov 15 Javascript
深入理解JavaScript中的并行处理
Sep 22 Javascript
详解vue的数据binding绑定原理
Apr 12 Javascript
解决layui的input独占一行的问题
Sep 10 Javascript
vue中渲染对象中属性时显示未定义的解决
Jul 31 Javascript
javaScript代码飘红报错看不懂?读完这篇文章再试试
Aug 19 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
星际争霸 Starcraft 编年史
2020/03/14 星际争霸
php 什么是PEAR?
2009/03/19 PHP
根据中文裁减字符串函数的php代码
2013/12/03 PHP
PHP实现通过正则表达式替换回调的内容标签
2015/06/15 PHP
大家须知简单的php性能优化注意点
2016/01/04 PHP
PHP实现上传多文件示例代码
2017/02/20 PHP
thinkPHP框架实现的简单计算器示例
2018/12/07 PHP
innerHTML,outerHTML,innerTEXT三者之间的区别
2007/01/28 Javascript
javascript cookies操作集合
2010/04/12 Javascript
Javascript实现的鼠标经过时播放声音
2010/05/18 Javascript
JavaScript中URL编码函数代码
2011/01/11 Javascript
jQuery插件animateSlide制作多点滑动幻灯片
2015/06/11 Javascript
javascript设计简单的秒表计时器
2020/09/05 Javascript
jquery获取文档高度和窗口高度汇总
2016/01/25 Javascript
AngularJS 使用 UI Router 实现表单向导
2016/01/29 Javascript
javascript鼠标右键菜单自定义效果
2020/12/08 Javascript
jQuery.Callbacks()回调函数队列用法详解
2016/06/14 Javascript
使用JavaScript获取URL中的参数(两种方法)
2016/11/16 Javascript
nodejs个人博客开发第六步 数据分页
2017/04/12 NodeJs
详解vue组件通信的三种方式
2017/06/30 Javascript
浅谈Express.js解析Post数据类型的正确姿势
2019/05/30 Javascript
vue axios post发送复杂对象问题
2019/06/04 Javascript
Vue项目打包编译优化方案
2020/09/16 Javascript
JavaScript检测是否开启了控制台(F12调试工具)
2020/10/02 Javascript
Python正则替换字符串函数re.sub用法示例
2017/01/19 Python
Python 实现购物商城,含有用户入口和商家入口的示例
2017/09/15 Python
详解如何在python中读写和存储matlab的数据文件(*.mat)
2018/02/24 Python
基于python实现简单日历
2018/07/28 Python
查看python安装路径及pip安装的包列表及路径
2019/04/03 Python
python networkx 根据图的权重画图实现
2019/07/10 Python
搞笑的获奖感言
2014/08/16 职场文书
农村党员干部承诺书
2015/05/04 职场文书
三国演义读书笔记
2015/06/25 职场文书
狂人日记读书笔记
2015/06/30 职场文书
pytorch 如何使用amp进行混合精度训练
2021/05/24 Python
MySQL创建定时任务
2022/01/22 MySQL