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 多种搜索引擎集成的页面实现代码
Jan 02 Javascript
Javascript学习笔记之 函数篇(三) : 闭包和引用
Nov 23 Javascript
jQuery手机拨号界面特效代码分享
Aug 27 Javascript
实例讲解JavaScript的Backbone.js框架中的View视图
May 05 Javascript
酷! 不同风格页面布局幻灯片特效js实现
Feb 19 Javascript
原生JS查找元素的方法(推荐)
Nov 22 Javascript
文件上传的几个示例分享【推荐】
Dec 16 Javascript
微信上传视频文件提示(推荐)
Nov 22 Javascript
vue 表单验证按钮事件交由父组件触发的方法
Dec 17 Javascript
Vue实现固定定位图标滑动隐藏效果
May 30 Javascript
微信小程序授权登陆及每次检查是否授权实例代码
Sep 18 Javascript
多种类型jQuery网页验证码插件代码实例
Jan 09 jQuery
详解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
Re:从零开始的异世界生活 第2季 开播啦
2020/07/24 日漫
PHP中的类-什么叫类
2006/11/20 PHP
php session应用实例 登录验证
2009/03/16 PHP
php数组索引的Key加引号和不加引号的区别
2014/08/19 PHP
ThinkPHP实现带验证码的文件上传功能实例
2014/11/01 PHP
PHP中字符串长度的截取用法示例
2017/01/12 PHP
PHPstorm启用自动换行的方法详解(IDE)
2020/09/17 PHP
JavaScript 继承详解 第一篇
2009/08/30 Javascript
JS实现根据出生年月计算年龄
2014/01/10 Javascript
JavaScript用Number方法实现string转int
2014/05/13 Javascript
jQuery循环滚动新闻列表示例代码
2014/06/17 Javascript
用javascript实现自动输出网页文本
2015/07/30 Javascript
JavaScript数据结构与算法之栈与队列
2016/01/29 Javascript
浅析创建javascript对象的方法
2016/05/13 Javascript
Jquery跨域获得Json的简单实例
2016/05/18 Javascript
深入理解Vue 的条件渲染和列表渲染
2017/09/01 Javascript
vue 插值 v-once,v-text, v-html详解
2018/01/19 Javascript
微信小程序列表中item左滑删除功能
2018/11/07 Javascript
jquery的$().each和$.each的区别
2019/01/18 jQuery
vue搜索和vue模糊搜索代码实例
2019/05/07 Javascript
SpringBoot在yml配置文件中配置druid的操作
2020/11/16 Javascript
[46:44]VG vs TNC Supermajor小组赛B组败者组决赛 BO3 第一场 6.2
2018/06/03 DOTA
解决tensorflow模型参数保存和加载的问题
2018/07/26 Python
Python读取csv文件分隔符设置方法
2019/01/14 Python
Python之lambda匿名函数及map和filter的用法
2019/03/05 Python
Python关于__name__属性的含义和作用详解
2020/02/19 Python
详解Ubuntu环境下部署Django+uwsgi+nginx总结
2020/04/02 Python
解决Python 函数声明先后顺序出现的问题
2020/09/02 Python
澳大利亚冲浪和时尚服装网上购物:SurfStitch
2017/07/29 全球购物
意大利香水和彩妆护肤品购物网站:Ditano
2017/08/13 全球购物
户籍证明的格式
2014/01/13 职场文书
十佳护士先进事迹
2014/05/08 职场文书
2014年党课学习材料
2014/05/11 职场文书
个人学习群众路线心得体会
2014/11/05 职场文书
学籍证明模板
2015/06/18 职场文书
高一地理教学工作总结
2015/08/12 职场文书