generator(生成器)是ES6标准引入的新的数据类型。一个generator看上去像一个函数,但可以返回多次。

ES6定义generator标准的哥们借鉴了Python的generator的概念和语法,如果你对Python的generator很熟悉,那么ES6的generator就是小菜一碟了。如果你对Python还不熟,赶快恶补Python教程!。

我们先复习函数的概念。一个函数是一段完整的代码,调用一个函数就是传入参数,然后返回结果:

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就是能够返回多次的“函数”?返回多次有啥用?

还是举个栗子吧。

我们以一个著名的斐波那契数列为例,它由01开头:

0 1 1 2 3 5 8 13 21 34 ...

要编写一个产生斐波那契数列的函数,可以这么写:

function fib(max) {vart,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) {vart,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 () {varr = 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()函数:

var current_id = 0;function next_id() {current_id ++;return current_id;
}

由于函数无法保存状态,故需要一个全局变量current_id来保存数字。

不用闭包,试用generator改写:

'use strict';
function* next_id() {
}// 测试:
varx,pass = true,g = next_id();
for (x = 1; x < 100; x ++) {if (g.next().value !== x) {pass = false;alert('测试失败!');break;}
}
if (pass) {alert('测试通过!');
}

js中的generator相关推荐

  1. JS中的 generator

      JS 中的 generator (生成器)和 Python 中的很相似.   一个generator看上去像一个函数,但可以返回多次.与函数不同的是,generator由function*定义(注 ...

  2. JS中的Generator函数

    Generator 函数是 ES6 提供的一种异步编程解决方案,它是一个状态机,封装了多个内部状态:它提供一种有效的方式来制作迭代器,并且能够处理无限数据流:当与Promises一起使用时,生成器可以 ...

  3. js中的yield、yield*和Generator函数

    基本概念 yield和yield*都是js中的关键字,他们不能直接使用:只能配合Generator进行使用:Generator是一种函数,声明方式和普通函数类似,只不过要在function后面加个*( ...

  4. es6 中的generator函数控制流程

    Generator函数跟普通函数的写法有非常大的区别: 一是,function关键字与函数名之间有一个星号: 二是,函数体内部使用yield语句,定义不同的内部状态(yield在英语里的意思就是&qu ...

  5. 掌握Node.js中的Async和Await

    在本文中,你将学习如何使用Node.js中的async函数(async/await)来简化callback或Promise. 异步语言结构在其他语言中已经存在了,像c#的async/await.Kot ...

  6. 【温故知新】——原生js中常用的四种循环方式

    一.引言 本文主要是利用一个例子,讲一下原生js中常用的四种循环方式的使用与区别: 实现效果: 在网页中弹出框输入0   网页输出"欢迎下次光临" 在网页中弹出框输入1   网页输 ...

  7. Js中函数式编程的理解

    函数式编程的理解 函数式编程是一种编程范式,可以理解为是利用函数把运算过程封装起来,通过组合各种函数来计算结果.函数式编程与命令式编程最大的不同其实在于,函数式编程关心数据的映射,命令式编程关心解决问 ...

  8. Js中Currying的应用

    Js中Currying的应用 柯里化Currying是把接受多个参数的函数变换成接受一个单一参数的函数,并且返回接受余下的参数且返回结果的新函数的技术,是函数式编程应用. 描述 如果说函数式编程中有两 ...

  9. 小白必看!JS中循环语句大集合

    摘要:JavaScript中,一共给开发者提供了一下几种循环语句,分别是while循环,do-while循环,for循环,for Each,for-in循环和for-of循环. 本文分享自华为云社区& ...

最新文章

  1. MongoDB内存映射文件
  2. HTML文件撰写的注意事项有哪些,CSS及HTML 常见误区和注意事项(一)
  3. HDU 4549 M斐波那契数列
  4. oracle loder nextval,ORA-07445: 出现异常错误: 核心转储
  5. java jconsole_java中jconsole命令的学习
  6. 太阳粒子是什么东西_太阳光子前世今生告诉我们现在享受之阳光是十几万年前诞生的老光...
  7. Linux 系统下载网址
  8. 背包九讲 ----- 01背包问题模版
  9. Chrome中使用showModalDialog无法接收返回值,解决方案
  10. LookUpEditPopup自动调整宽度
  11. windows下查看文件md5值
  12. 超级美女抽出滤镜抠图
  13. typescript4.2 新特性
  14. wps下载的简历无法删除空白页
  15. Tanzu系列:第8部分 - 创建tkg集群
  16. linux 执行计划任务
  17. html网页鼠标样式、css精灵、iconfont、过渡动画笔记
  18. 网址导航网站源码 Guojiz网址导航系统V 5.3正式版
  19. 使用taskset命令让进程运行在指定CPU上
  20. Java项目:JSP民宿预订网站信息管理平台

热门文章

  1. (~解题报告~)L1-019 谁先倒 (15分) ——17行代码AC
  2. 43行代码AC——例题6-8 树(Tree,UVa 548)——解题报告
  3. Python程序开发——第二章 条件语句和循环语句
  4. visual studio code Python终端运行_VS Code 6 月 Python 扩展更新
  5. web网络和http协议(了解域名和网页,制作第一个网页,了解http协议,流程和请求报文格式)
  6. shell脚本详解(二)——条件测试、if语句和case分支语句
  7. Java实现CSV读写操作源代码
  8. java webservice 常用_复杂对象类型的WebService高级部分
  9. python控制电脑关机_Python利用智能音箱语音控制电脑开关机
  10. java 及时释放内存_Java 内存释放