ES6 新特性——generator
generator 是 ES6 的新特性。
先来复习回顾一下函数的使用方法,函数是先声明再传值调用,如下:
function foo(x){
return x+x
}
var f1 = foo(2) // f1==4
return 语句是设定函数的返回值,一般可以声明一个变量去接收这个返回值(此处可以联想到闭包的应用)
如果没有再函数最后写 return 语句,默认就是 return undefined
下面引出 generator 的概念:
generator 和函数很想,只不过形式上有一些差异:
function* foo(x){
yield x + 1;
yield x + 2;
yield x + 3;
}
generator 与函数不同的地方是,generator 由 function*定义(注意多出来的“*”号),并且,除了 return 语句,还可以用 yield 返回多次。
那么 generator 就是一个可以返回多次的“函数”吗?
我们来看下面的例子:
以著名的斐波那契数列为例
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){
[a,b] = [b,a + b]
arr.push(b)
}
return arr;
}
这段代码是用 while 循环方法,每次都检测一个值然后去循环遍历
如果我们用 generator 改写就可以更优化:
function* fib(max){
var t,
a = 0,
b = 1,
n = 0;
while(n<max){
yield a;
[a,b] = [b,a+b];
n++;
}
return;
}
这个时候调用 fib(5),并不会像函数一样返回我们想要的结果,而是创建了一个对象。如果要让 generator 执行,需要再写一句 var f = fib(5),然后 f.next(),这样不停的写 next()方法直到返回 done:true,表示执行完成,程序暂停。
next()方法会执行 generator 的代码,每次遇到 yield x 就返回一个对象{value:x,done:true/false}。如果 done 为 true,则 value 就是 return 的返回值。
当执行到 done 为 true 就不再继续执行了。
第二个方法是直接用 for...of 循环迭代 generator 对象,这种方式不需要我们自己判断 done:
function* fib(max){
var t,
a = 0,
b = 1,
n = 0;
while(n<max){
yield a;
[a,b] = [b,a+b];
n++;
}
return;
}
for(var x of fib(10)){ //这里也可以用 in,都一样
console.log(x)
}
那么 generator 和普通函数相比,有什么好处?
因为 generator 可以在执行过程中多次返回,所以它看上去就像一个可以记住状态的函数,利用这一点,写一个 generator 就可以实现需要用面向对象才能实现的功能。例如,用一个对象来保存状态,我们需要这样写:
var fib = {
a:0,
b:1,
b: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 可以这么写:
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);
}
评论