语法
1.函数声明:函数名字前面带*
号,表示生成器
function *foo(){}
2.支持yield
语句
作用:暂停函数内部执行。yield
后面的语句暂停执行。函数内部可以有多个yield
语句,实现多次暂停
3.next()
方法
作用:开始执行或者从上次暂停的地方开始执行,停在函数结尾或者下一个yield
。还可以向yield
语句传递参数。
function *foo(x,y){
return x*y
}
var it =foo(6,7) //构造了名为it的迭代器,控制*foo开始
it.next()
//Object { value: 42, done: true }
返回的是这种形式的对象,有value
和done
属性
function *foo(x){
return x*(yield)
}
var it =foo(6)
it.next()
it.next(7)
//Object { value: 42, done: true }
我们看到yield和next存在一个匹配问题。比如上面的代码,第一个next并没有传入任何参数,第二个next传递参数,正确返回,这个时候他匹配了第一个yield
(即使传递了,浏览器也会默认没有传递,第一个next传递的参数是无效的)
搞清楚yield和next对应关系以后,就可以在脑子里面运行多个迭代器和多个生成器之间交替调用next,改变同一个变量。
var a=1
var b=2
function *foo(){
a++
yield
b=b*a
a=(yield b)+3
}
function *bar(){
b--
yield
a=(yield 8)+b
b=a*(yield 2)
}
function step(gen){
var it =gen()
var last
return function(){
last=it.next(last).value
}
}
var s1=step(foo)
var s2=step(bar)
s2() //a=1,b=1
s2() //a=1,b=1
s1() //a=2,b=1
s2() //a=9,b=1
s1() //a=9,b=9
s1() //a=12,b=9
s2() //a=12,b=18
console.log(a)
console.log(b)
如果你搞明白上面的过程之后,就会看到了异步操作的苗头了。
迭代器
用我自己的话来说,迭代器就差不多长这个样子
var something = (function(){
return {
[Symbol.iterator]: function(){ return this }
next:function(){
...//操作
return {done:false,value: }
}
}
})()
//手动调用next方法使用
something.next().value //1
但是当我们使用for...of
循环时,他会自动请求something
的迭代器。(就是已经自动调用了next
方法)。直到返回done:true
才会结束循环。
for (var v of something){
console.log(v)
if() break
}
我们看到上面简陋的迭代器是不会自己返回true
的。这个需要开发者在for...of
循环手动写出break
iterable(可迭代)
指一个包含可以在其值上迭代的迭代器对象。
调用Symbol.iterator
就会返回一个迭代器,就可以使用next
方法等
var a=[1,3,5,7,9]
var it =a[Symbol.iterator]()
it.next().value //1
it.next().value //3
...
停止生成器
当迭代器内部已经return
,那么生成器看起来就被挂起了。如果生成器内部有try...finally
语句。当迭代器return之后,就会执行finally语句内容。
强迫自己静下心来,看完了那几页晦涩的介绍生成器的书,最后给我来一句,这不重要,这不是本书的重点。外国人写书的口吻还能再幽默一点吗?气死我了!
生成器解决了什么问题
1.不需要闭包,也可以保存变量状态了。减少了使用闭包,内存泄漏的情况。
2.实现异步操作,在后面单开一篇介绍。