携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第17天,点击查看活动详情
大家好!我是前端爬楼工程师🚹,一个野生程序员。好奇新技术,仰慕牛大佬。如果喜欢我的文章,可以关注➕点赞,为我注入能量,与我一同成长吧~
生成器之前我们学习过了,他能产生值,并且再次调用的话,它产生的值和前面的值都有一定的关系。需要一个有状态的生产者能够记住最后一个值。我们可以实现闭包的版本。
var getVal = (function(){
var val = undefined;
return function (){
if(!val){
val = 1
}else{
val ++
}
return val
}
})()
getVal() // 1
getVal() // 2
对于资源受限的生产者来说,这种属于是资源泄漏的设计。
我们这个可以通过迭代器也能实现。
var getVal = (function(){
var val;
return {
[Symbol.iterator](){
return this
},
next(){
if(!val){
val = 1
}else{
val ++
}
return {done: val == 6, value:val}
}
}
})()
for(let i of getVal){console.log(val)} //遍历会在done为true的时候终止
getVal.next() //1
getVal.next() //2
iterable
上面的getVal对象是个迭代器,它的接口有一个next()方法,for..of循环会调用[Symbol.iterator]构建一个迭代器。也可以直接调用[Symbol.iterator]()的函数。
生成器迭代器
这是一个生成器function *foo(){}
它并不是迭代器,执行这个生成器,就会得到一个迭代器。var it = foo()
通过生成器实现getVal
function *getVal(){
var val
while(true){
if(val === undefined){
val = 1
}else{
val ++
}
yield val
}
}
var it = getVal()
it.next() // {value:1, done:false}
it.next() // {value:2, done:false}
yield 表示返回到主线程或事件循环队列中。 上述例子中·it.next()·可以一直调用,如何正常停止它呢
for(let v of getVal()){
console.log(v)
if(v>6){
break;
}
}
for...of循环中的break调用,生成器中的迭代器永远留在了挂起状态。
for..of循环结束后会给生成器发送一个信号。这个可以通过try{..}finally{..}实现接收
function *getVal(){
try{
var val
while(true){
if(val === undefined){
val = 1
}else{
val ++
}
yield val
}
}finally{
console.log('clean up!!')
}
}
for(let v of getVal()){
console.log(v)
if(v>6){
break;
}
}
// 1 2 3 4 5 6 clean up!!
外部也可以通过return手工终止生成器
var it = getVal()
for(let v of it){
console.log(v)
if(v>6){
it.return("end ...").value;
}
}
通过return我们已经把生成器的迭代器设置为done:true。所以for..of在下一个循环里终止。