怎么存储所有的斐波那契数列呢?
Generator
函数是 ES6 提供的一种异步编程解决方案,和普通的函数相似,但是又有着不同。
下面是常见的用法:
1 2 3 4 5 6 7 8
| function* helloGenerator() { yield 'Hello Bao'; yield 'Hello Leo'; return 'Hello Saro'; }
var hello = helloGenerator();
|
和我们常见的函数相比,关键字 function
后加了 *
字符,并且方法体中使用了 yield
关键字。(函数名称并不一定要以 -Generator
作为后缀,这里只是标记其为生成器函数)。当这个生成器函数“执行”之后,变量 hello
并不是表示返回值 'Hello Saro'
。在控制台打印 hello
,输出为 {}
。这其实表示的是一个指向内部状态的指针对象,也就是一个 遍历器对象
。
可以使用 hello.next()
将状态指向下一个。
1 2 3 4
| hello.next(); hello.next(); hello.next(); hello.next();
|
生成器函数执行时,遇到 yield
会暂停执行,使用 next()
可以继续执行,并且输出暂停处的结果。
由此可见,yield
和 return
功能上类似,只不过 yield
可以在 next()
后继续从断点处继续执行,而 return
则退出方法。
值得注意的是:
yield 后的函数或者表达式是惰性执行的,只有 yield 之后的代码段执行的时候,才会进行语法校验。
next
方法的参数
yield
本身是没有返回值的,可以使用 next()
传递进去一个参数,用于代替前一个 yield
的返回值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| function* split(num) { var x = yield num / 2; return x; }
var ss = split(100);
ss.next(); ss.next(100);
ss.next(); ss.next();
|
其他的方法
Generator.prototype.return()
用于中断当前的生成器函数,直接返回。
1 2 3 4 5 6 7 8 9 10 11 12
| function* helloGenerator() { yield 'Hello Bao'; yield 'Hello Leo'; return 'Hello Saro'; }
var hello = helloGenerator();
hello.next(); hello.return('return'); hello.next();
|
Generator.prototype.throw()
用于向生成器函数内部对应的 yield
,抛入异常,如果生成器函数内部不捕获异常,则会中断整个生成器。
1 2 3 4 5 6 7 8 9 10 11
| function* helloGenerator() { yield 'Hello Bao'; yield 'Hello Leo'; return 'Hello Saro'; }
var hello = helloGenerator();
console.log(hello.next()); console.log(hello.throw('throw')); console.log(hello.next());
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| function* helloGenerator() { try { yield 'Hello Bao'; yield 'Hello Leo'; } catch (error) { console.log('error'); } return 'Hello Saro'; }
var hello = helloGenerator();
console.log(hello.next()); console.log(hello.throw('throw')); console.log(hello.next());
|
斐波那契数列的实现
回过头来,看一下开始的那个问题,可以用构造器函数构建一个斐波那契数列:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| function* fibonacci() { let prev = 0; let curr = 1; let temp = 0; yield prev; yield curr; while(true) { temp = curr; prev = temp; curr = prev + curr; yield curr; } }
function* fibonacci() { let [prev, curr] = [0, 1]; yield prev; yield curr; while(true) { [prev, curr] = [curr, prev + curr]; yield curr; } }
var f = fibonacci(); for (let i = 0; i < 10; i++) { console.log(f.next().value); }
|
最后
这里介绍了生成器函数的基本使用,有关更为详细的介绍,以及和 Promise 的混合使用,可以参考阮一峰老师的文章Generator 函数的语法 和 Generator 函数的异步应用。