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之卸载鼠标事件的代码
May 14 Javascript
jquery 定位input元素的几种方法小结
Jul 28 Javascript
js用拖动滑块来控制图片大小的方法
Feb 27 Javascript
javascript实现的多个层切换效果通用函数实例
Jul 06 Javascript
jQuery实现自定义checkbox和radio样式
Jul 13 Javascript
Boostrap实现的登录界面实例代码
Oct 09 Javascript
BootStrap按钮标签及基本样式
Nov 23 Javascript
form表单数据封装成json格式并提交给服务器的实现方法
Dec 14 Javascript
angular.js和vue.js中实现函数去抖示例(debounce)
Jan 18 Javascript
Angular2实现的秒表及改良版示例
May 10 Javascript
laypage+SpringMVC实现后端分页
Jul 27 Javascript
ES6 proxy和reflect的使用方法与应用实例分析
Feb 15 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
Ajax PHP分页演示
2007/01/02 PHP
PHPMYADMIN导入数据最大为2M的解决方法
2012/04/23 PHP
使用图灵api创建微信聊天机器人
2015/07/23 PHP
PHP MVC框架skymvc支持多文件上传
2016/05/26 PHP
javascript css在IE和Firefox中区别分析
2009/02/18 Javascript
Javascript 通过json自动生成Dom的代码
2010/04/01 Javascript
JQuery从头学起第二讲
2010/07/04 Javascript
JavaScript 类型的包装对象(Typed Wrappers)
2011/10/27 Javascript
JQuery入门—编写一个简单的JQuery应用案例
2013/01/03 Javascript
Ubuntu 16.04 64位中搭建Node.js开发环境教程
2016/10/19 Javascript
详解MVC如何使用开源分页插件(shenniu.pager.js)
2016/12/16 Javascript
JavaScript中的遍历详解(多种遍历)
2017/04/07 Javascript
JavaScript实现的选择排序算法实例分析
2017/04/14 Javascript
Element input树型下拉框的实现代码
2018/12/21 Javascript
ES6 Array常用扩展的应用实例分析
2019/06/26 Javascript
全局安装 Vue cli3 和 继续使用 Vue-cli2.x操作
2020/09/08 Javascript
antd design table更改某行数据的样式操作
2020/10/31 Javascript
php使用递归与迭代实现快速排序示例
2014/01/23 Python
python回调函数的使用方法
2014/01/23 Python
python学习之面向对象【入门初级篇】
2017/01/21 Python
python的pdb调试命令的命令整理及实例
2017/07/12 Python
selenium python浏览器多窗口处理代码示例
2018/01/15 Python
python学习笔记--将python源文件打包成exe文件(pyinstaller)
2018/05/26 Python
Python基于plotly模块实现的画图操作示例
2019/01/23 Python
python线程的几种创建方式详解
2019/08/29 Python
python字符串格式化方式解析
2019/10/19 Python
Python上下文管理器用法及实例解析
2019/11/11 Python
完美解决pyinstaller打包报错找不到依赖pypiwin32或pywin32-ctypes的错误
2020/04/01 Python
《一件运动衫》教学反思
2014/02/19 职场文书
《社戏》教学反思
2014/04/15 职场文书
《画家乡》教学反思
2014/04/22 职场文书
2014年幼儿园工作总结
2014/11/10 职场文书
学籍证明模板
2014/11/21 职场文书
毕业论文答辩开场白
2015/05/27 职场文书
七年级作文之雪景
2019/11/18 职场文书
python3 删除所有自定义变量的操作
2021/04/08 Python