前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >《你不知道的JavaScript》:生成器中的生产者和迭代器

《你不知道的JavaScript》:生成器中的生产者和迭代器

作者头像
前端_AWhile
发布2019-08-29 13:11:37
4380
发布2019-08-29 13:11:37
举报
文章被收录于专栏:前端一会前端一会

生成器的一种有趣用法是作为一种产生值的方式。而这也是“生成器”这个名称的最初使用场景。前面说过生成器函数每次调用都会创建一个迭代器实例。这个迭代器实例有next()方法,与生成器函数中的yield关键字组合可以完成消息传递。

那怎么理解这个生成器和迭代器呢?从字面意思理解,可以理解成生成器是值的生产者,而迭代器是值的获取者。生成器函数调用产生迭代器,迭代器用next()方法来执行生成器函数。

这里面需要注意一个关键点,迭代器每次next()要想实现当前值与前面一个值有特定的关系,就需要生成器能保持状态来记住其生成的最后一个值。

首先可以实现一个使用函数闭包的版本:

代码语言:javascript
复制
var clourseSomething = (function(){
    var nextVal;
    return function(){
        if(nextVal === undefined){
            nextVal = 1;
        }else {
            nextVal = ( nextVal * 3 ) + 6;
        }
        return nextVal;
    }
})()

clourseSomething();    // 1
clourseSomething();    // 9
clourseSomething();    // 33
clourseSomething();    // 105

使用闭包的话,从执行粒度上看函数完成一次执行时就已经计算出下一个值,但实际上按照正常思路,应该是希望直到下一次clourseSomething()调用发生时才计算下一个值(即nextVal)。否则通常来说对更持久化或比起简单数字资源更受限的生产者来说,这可能是资源泄露的一种设计。唔,这也是闭包所容易为人诟病的一点。

这个时候就可以采用一种常见的设计模式,迭代器模式。迭代器是一个定义良好的接口,用于从一个生产者一步步得到一系列值,就是每次想要从生产者得到下一个值时调用next()。

代码语言:javascript
复制
var something = (function () {
    var nextVal;

    return {
        //for..of..循环需要
        [Symbol.iterator]: function(){ return this; },

        //标准迭代器接口方法
        next: function () {
            if(nextVal === undefined){
                nextVal = 1;
            }else {
                nextVal = ( nextVal*3 ) + 10;
            }
            return {done: false, value: nextVal}
        }
    }
})()

console.log(something.next().value);      // 1
console.log(something.next().value);      // 13
console.log(something.next().value);      // 49

next()调用返回一个对象。这个对象有两个属性:done是一个布尔值,标识迭代器的完成状态;value中放置迭代值。

ES6中新增了for...of...方法,这意味着可以通过原生语法循环自动迭代标准迭代器(接上例somthing):

代码语言:javascript
复制
for(var v of something){
    console.log(v);

    //不要死循环
    if(v > 500){
        break;
    }
}
// 1  13  49  157  481  1453

for..of循环在每次迭代中自动调用next(),它不会向next()中传入任何值,并且会在接收done:true时停止。上例中迭代器something总是返回done:false,这个for..of循环会永远运行下去,所以在测试循环里放入break条件。

除了构造自己的迭代器,许多javascript的内建数据结构(从ES6开始),比如array,也有默认的迭代器:

代码语言:javascript
复制
var arr = [10, 2, 3, 4, 5];
for(var v of arr){
    console.log(v);
}
// 10  2  3  4  5

for...of循环向arr请求它的迭代器,并自动使用这个迭代器来迭代遍历arr的值。

可能有朋友对迭代器something中的Symbol.iterator属性不是很了解,它是迭代器的定义标识,是for...of..工作的基础,具体将在下篇解释。

-------------------------------- 热门文章 --------------------------------

设计模式>>>

javascript设计模式一: 单例模式

javascript设计模式二:策略模式

javascript设计模式三:代理模式

javascript设计模式四:迭代器模式

javascript设计模式五:原型模式

javascript设计模式六:发布-订阅模式(观察者模式)

javascript设计模式七:模板方法模式

javascript设计模式八:职责链模式

javascript设计模式九:中介者模式

javascript设计模式十:装饰者模式

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-01-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端小二 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档