function RangeIterator(range){
this.range = range;
this.current = this.range.low;
}
RangeIterator.prototype.next = function(){
if (this.current > this.range.high)
throw StopIteration;
else
return this.current++;
};
我们的 RangeIterator 通过 range 实例来实例化,同时维持一个 current 属性来跟踪当前序列的位置。
最后,为了让 RangeIterator 可以和 Range 结合起来,我们需要为 Range 添加一个特殊的 __iterator__ 方法。当我们试图去迭代一个 Range 时,它将被调用,而且应该返回一个实现了迭代逻辑的 RangeIterator 实例。
复制代码 代码如下:
Range.prototype.__iterator__ = function(){
return new RangeIterator(this);
};
完成我们的自定义迭代器后,我们就可以迭代一个范围实例:
复制代码 代码如下:
var range = new Range(3, 5);
for (var i in range)
print(i); //输出 3,然后 4,然后 5
生成器:一种更好的方式来构建迭代器
虽然自定义的迭代器是一种很有用的工具,但是创建它们的时候要仔细规划,因为需要显式的维护它们的内部状态。
生成器提供了很强大的功能:它允许你定义一个包含自有迭代算法的函数, 同时它可以自动维护自己的状态。
生成器是可以作为迭代器工厂的特殊函数。如果一个函数包含了一个或多个 yield 表达式,那么就称它为生成器(译者注:Node.js 还需要在函数名前加 * 来表示)。
注意:只有 HTML 中被包含在 <script type="application/javascript;version=1.7"> (或者更高版本)中的代码块才可以使用 yield 关键字。XUL (XML User Interface Language) 脚本标签不需要指定这个特殊的代码块也可以访问这些特性。
当一个生成器函数被调用时,函数体不会即刻执行,它会返回一个 generator-iterator 对象。每次调用 generator-iterator 的 next() 方法,函数体就会执行到下一个 yield 表达式,然后返回它的结果。当函数结束或者碰到 return 语句,一个 StopIteration 异常会被抛出。
用一个例子来更好的说明:
复制代码 代码如下:
function simpleGenerator(){
yield "first";
yield "second";
yield "third";
for (var i = 0; i < 3; i++)
yield i;
}
var g = simpleGenerator();
print(g.next()); //输出 "first"
print(g.next()); //输出 "second"
print(g.next()); //输出 "third"
print(g.next()); //输出 0
print(g.next()); //输出 1
print(g.next()); //输出 2
print(g.next()); //抛出 StopIteration 异常
生成器函数可以被一个类直接的当做 __iterator__ 方法使用,在需要自定义迭代器的地方可以有效的减少代码量。我们使用生成器重写一下 Range :
复制代码 代码如下:
function Range(low, high){
this.low = low;
this.high = high;
}
Range.prototype.__iterator__ = function(){
for (var i = this.low; i <= this.high; i++)
yield i;
};
var range = new Range(3, 5);
for (var i in range)
print(i); //输出 3,然后 4,然后 5
不是所有的生成器都会终止,你可以创建一个代表无限序列的生成器。下面的生成器实现一个斐波那契序列,就是每一个元素都是前面两个的和:
复制代码 代码如下:
function fibonacci(){
var fn1 = 1;
var fn2 = 1;
while (1) {
var current = fn2;
fn2 = fn1;
fn1 = fn1 + current;
yield current;
}
}
var sequence = fibonacci();
print(sequence.next()); // 1
print(sequence.next()); // 1
print(sequence.next()); // 2
print(sequence.next()); // 3
print(sequence.next()); // 5
print(sequence.next()); // 8
print(sequence.next()); // 13