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 相关文章推荐
Firefox/Chrome/Safari的中可直接使用$/$$函数进行调试
Feb 13 Javascript
html文件中jquery与velocity变量中的$冲突的解决方法
Nov 01 Javascript
JS实现具备延时功能的滑动门菜单效果
Sep 17 Javascript
AngularJS基础 ng-repeat 指令简单示例
Aug 03 Javascript
JS随机排序数组实现方法分析
Oct 11 Javascript
WebSocket的通信过程与实现方法详解
Apr 29 Javascript
在angular 6中使用 less 的实例代码
May 13 Javascript
iview实现图片上传功能
Jun 29 Javascript
完美解决通过IP地址访问VUE项目的问题
Jul 18 Javascript
JavaScript实现鼠标移入随机变换颜色
Nov 24 Javascript
详解Vue的sync修饰符
May 15 Vue.js
vue ant design 封装弹窗表单的使用
Jun 01 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
2020最新CPU的性能排名
2020/04/02 数码科技
WINDOWS 2000下使用ISAPI方式安装PHP
2006/09/05 PHP
PHP 文章中的远程图片采集到本地的代码
2009/07/30 PHP
在PHP中PDO解决中文乱码问题的一些补充
2010/09/06 PHP
解析在PHP中使用mysqli扩展库对mysql的操作
2013/07/03 PHP
[原创]PHP简单开启curl的方法(测试可行)
2016/01/11 PHP
Yii2实现log输出到file及database的方法
2016/11/12 PHP
php版阿里大于(阿里大鱼)短信发送实例详解
2016/11/30 PHP
基于php双引号中访问数组元素报错的解决方法
2018/02/01 PHP
PHP-FPM 设置多pool及配置文件重写操作示例
2019/10/02 PHP
js中string转int把String类型转化成int类型
2014/08/13 Javascript
编写简单的jQuery提示插件
2014/12/21 Javascript
两种JS实现屏蔽鼠标右键的方法
2020/08/20 Javascript
正则表达式,替换所有HTML标签的简单实例
2016/11/28 Javascript
jQuery基于xml格式数据实现模糊查询及分页功能的方法
2016/12/25 Javascript
VUE axios上传图片到七牛的实例代码
2017/07/28 Javascript
完美解决mui框架off-canvas侧滑超出部分隐藏无法滚动的问题
2018/01/25 Javascript
微信小程序实现星级评价效果
2018/12/28 Javascript
vue项目打包后提交到git上为什么没有dist这个文件的解决方法
2020/09/16 Javascript
解决VUE 在IE下出现ReferenceError: Promise未定义的问题
2020/11/07 Javascript
python基础_文件操作实现全文或单行替换的方法
2017/09/04 Python
pycharm远程调试openstack代码
2017/11/21 Python
Python时间戳使用和相互转换详解
2017/12/11 Python
Python实现自动发送邮件功能
2021/03/02 Python
python生成不重复随机数和对list乱序的解决方法
2018/04/09 Python
在jupyter notebook中调用.ipynb文件方式
2020/04/14 Python
使用Tensorflow-GPU禁用GPU设置(CPU与GPU速度对比)
2020/06/30 Python
维珍澳洲航空官网:Virgin Australia
2017/09/08 全球购物
掌上明珠Java程序员面试总结
2016/02/23 面试题
电大毕业生自我鉴定
2013/11/10 职场文书
早读迟到检讨书
2014/01/24 职场文书
工程承诺书怎么写
2014/05/24 职场文书
公司委托书格式范本
2014/09/16 职场文书
2019年家电促销广告语集锦
2019/10/21 职场文书
Mysql 如何查询时间段交集
2021/06/08 MySQL
Windows10安装Apache2.4的方法步骤
2022/06/25 Servers