发电机(生成器)是ES6标准引入的新的数据类型。一个发电机看上去像一个函数,但可以返回多次。
我们先复习函数的概念。一个函数是一段完整的代码,调用一个函数就是传入参数,然后返回结果:
函数foo (x) { 返回x + x; } var r=foo (1);//调用foo函数 >之前函数在执行过程中,如果没有遇到<代码> 代码>返回语句(函数末尾如果没有<代码>返回> 代码,就是隐含的<代码>返回定义> 代码;),控制权无法交回被调用的代码。
发电机跟函数很像,定义如下:
*函数foo (x) { 产生x + 1; 产生x + 2; 返回x + 3; } >之前发电机和函数不同的是,发电机由<代码>函数* 代码>定义(注意多出的<代码> * 代码>号),并且,除了<代码> 代码>返回语句,还可以用<代码> 代码>收益率返回多次。
大多数同学立刻就晕了,发电机就是能够返回多次的“函数”?返回多次有啥用?
还是举个栗子吧。
我们以一个著名的斐波那契数列为例,它由0,1开头:
0 1 1 2 3 5 8 13 21 34… >之前要编写一个产生斐波那契数列的函数,可以这么写:
函数fib (max) { var t, 一个=0, b=1, arr=[0, 1]; 而(加勒比海盗。长度& lt;max) { t=a + b; a=b; b=t; arr.push (t); } 返回arr; }//测试: 心房纤颤(5);//[0,1,1,2,3] 心房纤颤(10);//[0,1,1,2,3,5,8,13日,21日,34) >之前函数只能返回一次,所以必须返回一个<代码> 代码>数组。但是,如果换成发电机,就可以一次返回一个数,不断返回多次。用发电机改写如下:
函数* fib (max) { var t, 一个=0, b=1, n=1; 而(n & lt;max) { 产生; t=a + b; a=b; b=t; n + +; } 返回一个; } >之前直接调用试试:
代码如下:
心房纤颤(5);//fib {[[GeneratorStatus]]:“暂停”,[[GeneratorReceiver]]:窗口}
直接调用一个发电机和调用函数不一样,<代码> fib(5)> 代码仅仅是创建了一个发电机对象,还没有去执行它。
调用发电机对象有两个方法,一是不断地调用发电机对象的<代码> next() 代码>方法:
var f=fib (5); f.next ();//{值:0,完成:假} f.next ();//{价值:1、完成:假} f.next ();//{价值:1、完成:假} f.next ();//{完成值:2日:假} f.next ();//{值:3,完成:真}<代码> next() 代码>方法会执行发生器的代码,然后,每次遇到<代码>产量x> 代码;就返回一个对象<代码>{值:x,完成:真/假}> 代码,然后“暂停”。返回的<代码> 代码>就价值是<代码>产量> 代码的返回值,<代码> 代码>完成表示这个发电机是否已经执行结束了。如果做<代码> 代码>为<代码> true> 代码,则<代码> 代码>就价值是<代码> 代码>返回的返回值。
当执行到做<代码> 代码>为<代码> 代码>时,这个发电机对象就已经全部执行完毕,不要再继续调用<代码> next() 代码>了。
第二个方法是直接用<代码>……> 代码的循环迭代发电机对象,这种方式不需要我们自己判断<代码> 代码>:
(var x (fib (5)) { console.log (x);//依次输出0,1,1,2,3 }发电机和普通函数相比,有什么用?
因为发电机可以在执行过程中多次返回,所以它看上去就像一个可以记住执行状态的函数,利用这一点,写一个发电机就可以实现需要用面向对象才能实现的功能,例如,用一个对象来保存状态,得这么写:
var fib={ 答:0, b: 1、 n: 0, 马克斯:5 下:函数(){ var r=this.a, t=? this.b; 这一点。一个=this.b; 这一点。b=t; 如果这一点。n & lt;this.max) { 这一点。n + +; 返回r; 其他}{ 返回未定义; } }JavaScript之生成器_动力节点Java学院整理