函数
先理解函数:
先看例子:
函数一段完整的代码,调用一个函数就是传入参数,然后返回结果。
function foo(x){
return x*x;
}
var f1 = foo(2); //调用函数,结果是4
在调用函数的过程中,如果函数没有遇到return或者是隐含的return,那么控制权无法交回被调用的代码。
Generator
Generator其实和函数是很像的,看一下例子:
function* fun(x){
yield x + 1;
yield x + 2;
return yield x + 3;
}
var f = fun(2);
f.next(); //3
f.next();//4
f.next();//5
备注:
Generator关键字是function*,要比function多一个*。
并且除了return,还可以使用yield返回多次。
举例说明:
//斐波拉契数列
//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;
}
//使用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 n;
}
fib(5); // fib {[[GeneratorStatus]]: “suspended”, [[GeneratorReceiver]]: Window}
结果不是我们想要的,为什么呢?
直接调用一个generator和调用函数不一样,fib(5)仅仅是创建了一个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是否已经执行结束了。如果done为true,则value就是return的返回值。
第二个方法是直接用for … of循环迭代generator对象,这种方式不需要我们自己判断done:
for (var x of fib(5)) {
console.log(x); // 依次输出0, 1, 1, 2, 3
}
generator和普通函数相比,有什么用?
因为generator可以在执行过程中多次返回,所以它看上去就像一个可以记住执行状态的函数,利用这一点,写一个generator就可以实现需要用面向对象才能实现的功能。
练习
要生成一个自增的ID,可以编写一个next_id()函数:
var current_id = 0;
function next_id() {
current_id ++;
return current_id;
}
由于函数无法保存状态,故需要一个全局变量current_id来保存数字。
不用闭包,试用generator改写:
function* next_id() {
var x = 1;
while(true){
yield x++;
}
}
测试就可以通过。