生成器产生值

501 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 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在下一个循环里终止。