Generator-ing Values

在前一篇翻译的文章中,我们描述关于generator的使用,这里我们主要讨论的是迭代器的话题,以及迭代器是如何与generator关联的并且用generator来生成值的。

想一想现在有这么一个需求,它要求生成一系列的数字,并且每个数字都与前一个数字有一个定义好的内在关系。


首先我们可以直接用闭包实现这个功能。

var gimmeSomething = (function(){
    var nextVal;

    return function(){
        if (nextVal === undefined) {
            nextVal = 1;
        }
        else {
            nextVal = (3 * nextVal) + 6;
        }

        return nextVal;
    };
})();

gimmeSomething();       // 1
gimmeSomething();       // 9
gimmeSomething();       // 33
gimmeSomething();       // 105
这里需要注意的一点是这样的设计存在内存泄露的隐患。具体可以参见(http://www.ibm.com/developerworks/cn/web/wa-jsmemory/)

接下来我们看看通过迭代器接口的实现:

var something = (function(){
    var nextVal;

    return {
        // needed for `for..of` loops
        [Symbol.iterator]: function(){ return this; },

        // standard iterator interface method
        next: function(){
            if (nextVal === undefined) {
                nextVal = 1;
            }
            else {
                nextVal = (3 * nextVal) + 6;
            }

            return { done:false, value:nextVal };
        }
    };
})();

something.next().value;     // 1
something.next().value;     // 9
something.next().value;     // 33
something.next().value;     // 105
next()的调用会返回两个属性的对象:done是布尔值类型标记迭代器的完成状态。value持有迭代值。

ES6加入了for .. of的循环,这意味着便准的迭代器可以使用原生的loop循环。

for (var v of something) {
    console.log( v );

    // don't let the loop run forever!
    if (v > 500) {
        break;
    }
}
// 1 9 33 105 321 969
这里需要注意的是,因为前面定义的迭代器接口会始终返回done:false,所以for loop会永远的循环下去,这就是为什么在这里加入了break条件。

当然对于迭代器而言,可以一支运行而不结束,但是对于有些情况迭代器会运行有限的集合,最后返回done:true;


for loop循环自动的在每次迭代的时候调用next,它不会传递任何值在next中,并且在已接受到done:true的时候结束。

在ES6中许多内建的数据结构诸如数组都有默认的迭代器。

var a = [1,3,5,7,9];

for (var v of a) {
    console.log( v );
}
// 1 3 5 7 9

something在我们的例子中被称为迭代器。因为它有next方法在接口上。但有一个非常接近的相关术语叫做迭代对象,它是一个对象包含有迭代器。

从一个迭代对象中获取一个迭代器的方法是迭代对象一定会有一个function带有symbol.iterator标记,当这个函数被调用时返回一个迭代器。一般来讲,每次调用都回返回一个全新的迭代器。

a在前面代码中是一个迭代对象,for loop会自动地调用它的symbol.iterator函数构建一个迭代器。

下面是手动调用的例子

var a = [1,3,5,7,9];

var it = a[Symbol.iterator]();

it.next().value;    // 1
it.next().value;    // 3
it.next().value;    // 5
重点来了,generator的迭代器

现在我们把注意力放到generator上,一个generator可以被看作为producer of values, 通过迭代器接口的next方法抽取值。

generator本身并不是迭代对象,虽然看起来很相似,执行generator,得到一个迭代器。

function *foo(){ .. }

var it = foo();
现在用一个generator来实现一个生成无限数字序列的函数

function *something() {
    var nextVal;

    while (true) {
        if (nextVal === undefined) {
            nextVal = 1;
        }
        else {
            nextVal = (3 * nextVal) + 6;
        }

        yield nextVal;
    }
}
这里,只要我们请求something, while loop告诉我们generator会一直在运行去生成新的值,




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值