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 相关文章推荐
JavaScipt基本教程之JavaScript语言的基础
Jan 16 Javascript
取得窗口大小 兼容所有浏览器的js代码
Aug 09 Javascript
Jquery ajax执行顺序 返回自定义错误信息(实例讲解)
Nov 06 Javascript
JavaScript DOM进阶方法
Apr 13 Javascript
JavaScript知识点总结(十六)之Javascript闭包(Closure)代码详解
May 31 Javascript
Bootstrap基本样式学习笔记之表格(2)
Dec 07 Javascript
js仿微信语音播放实现思路
Dec 12 Javascript
走进javascript——不起眼的基础,值和分号
Feb 24 Javascript
jQuery实现火车票买票城市选择切换功能
Sep 15 jQuery
解决v-for中使用v-if或者v-bind:class失效的问题
Sep 25 Javascript
微信小程序+云开发实现欢迎登录注册
May 24 Javascript
JavaScript实现图片轮播特效
Oct 23 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不用递归实现无限分级的例子分享
2014/04/18 PHP
PHP实现对图片的反色处理功能【测试可用】
2018/02/01 PHP
javascript 自定义事件初探
2009/08/21 Javascript
关于js类的定义
2011/06/28 Javascript
网页中返回顶部代码(多种方法)另附注释说明
2013/04/24 Javascript
浅析js封装和作用域
2013/07/09 Javascript
javascript获取web应用根目录的方法
2014/02/12 Javascript
javascript中AJAX用法实例分析
2015/01/30 Javascript
jQuery 如何给Carousel插件添加新的功能
2016/04/18 Javascript
jQuery实现页面顶部下拉广告
2016/12/30 Javascript
Vue 单文件中的数据传递示例
2017/03/21 Javascript
vue Element-ui input 远程搜索与修改建议显示模版的示例代码
2017/10/19 Javascript
解决vue-router中的query动态传参问题
2018/03/20 Javascript
Javascript的this详解
2019/03/23 Javascript
使用weixin-java-miniapp配置进行单个小程序的配置详解
2019/03/29 Javascript
node获取客户端ip功能简单示例
2019/08/24 Javascript
ES2020 新特性(种草)
2020/01/12 Javascript
JS localStorage存储对象,sessionStorage存储数组对象操作示例
2020/02/15 Javascript
TypeScript 运行时类型检查补充工具
2020/09/28 Javascript
python以环状形式组合排列图片并输出的方法
2015/03/17 Python
浅谈Series和DataFrame中的sort_index方法
2018/06/07 Python
python2.x实现人民币转大写人民币
2018/06/20 Python
Python+OpenCV图片局部区域像素值处理详解
2019/01/23 Python
Python 利用切片从列表中取出一部分使用的方法
2019/02/01 Python
pycharm实现在虚拟环境中引入别人的项目
2020/03/09 Python
python:批量统计xml中各类目标的数量案例
2020/03/10 Python
Python中Selenium库使用教程详解
2020/07/23 Python
python3访问字典里的值实例方法
2020/11/18 Python
英国家庭家具、照明和花园家具购物网站:Furniture123
2018/12/31 全球购物
先进工作者获奖感言
2014/02/08 职场文书
2014村务公开实施方案
2014/02/25 职场文书
计算机维护专业推荐信
2014/02/27 职场文书
承诺书的格式范文
2014/03/28 职场文书
班主任自我评价范文
2015/03/11 职场文书
小学科学课教学反思
2016/02/23 职场文书
Python函数对象与闭包函数
2022/04/13 Python