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编程的10个实用小技巧
Apr 18 Javascript
JS控制表格实现一条光线流动分割行的方法
Mar 09 Javascript
解决jQuery使用JSONP时产生的错误
Dec 02 Javascript
AngularJs Understanding the Model Component
Sep 02 Javascript
带你快速理解javascript中的事件模型
Aug 14 Javascript
Angular实现类似博客评论的递归显示及获取回复评论的数据
Nov 06 Javascript
Vue路由钩子之afterEach beforeEach的区别详解
Jul 15 Javascript
Vue实现一个图片懒加载插件
Mar 11 Javascript
说说如何使用Vuex进行状态管理(小结)
Apr 14 Javascript
ES6顶层对象、global对象实例分析
Jun 14 Javascript
JS实现排行榜文字向上滚动轮播效果
Nov 26 Javascript
在vue中使用echarts(折线图的demo,markline用法)
Jul 20 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 split汉字
2009/06/05 PHP
php通用防注入程序 推荐
2011/02/26 PHP
php class中public,private,protected的区别以及实例分析
2013/06/18 PHP
PHP入门教程之PHP操作MySQL的方法分析
2016/09/11 PHP
php使用SAE原生Mail类实现各种类型邮件发送的方法
2016/10/10 PHP
通过php动态传数据到highcharts
2017/04/05 PHP
解决laravel groupBy 对查询结果进行分组出现的问题
2019/10/09 PHP
JQuery中判断一个元素下面是否有内容或者有某个标签的判断代码
2012/02/02 Javascript
HTML上传控件取消选择
2013/03/06 Javascript
json数据的列循环示例
2013/09/06 Javascript
各浏览器对document.getElementById等方法的实现差异解析
2013/12/05 Javascript
setInterval计时器不准的问题解决方法
2014/05/08 Javascript
JavaScript中判断页面关闭、页面刷新的实现代码
2014/08/27 Javascript
基于jQuery+Cookie实现的防止刷新的在线考试倒计时
2015/06/19 Javascript
vue2.0实战之基础入门(1)
2017/03/27 Javascript
详解vue2.0 transition 多个元素嵌套使用过渡
2017/06/19 Javascript
vue父组件通过props如何向子组件传递方法详解
2017/08/16 Javascript
JS去掉字符串末尾的标点符号及删除最后一个字符的方法
2017/10/24 Javascript
React Native时间转换格式工具类分享
2017/10/24 Javascript
Vuejs 单文件组件实例详解
2018/02/09 Javascript
详解vue中组件参数
2018/07/09 Javascript
微信小程序 点击切换样式scroll-view实现代码实例
2019/10/11 Javascript
selenium+java中用js来完成日期的修改
2019/10/31 Javascript
Python中暂存上传图片的方法
2015/02/18 Python
Python httplib模块使用实例
2015/04/11 Python
python输出指定月份日历的方法
2015/04/23 Python
python基础知识小结之集合
2015/11/25 Python
浅谈Python实现Apriori算法介绍
2017/12/20 Python
解决Jupyter NoteBook输出的图表太小看不清问题
2020/04/16 Python
Python操作Elasticsearch处理timeout超时
2020/07/17 Python
财务管理职业生涯规划范文
2013/12/27 职场文书
学生评语大全
2014/04/18 职场文书
公安局副政委班子个人对照检查材料
2014/10/04 职场文书
支行行长岗位职责
2015/02/15 职场文书
地道战观后感400字
2015/06/04 职场文书
Springboot集成阿里云OSS上传文件系统教程
2021/06/28 Java/Android