for…in 循环可以被用来替换显式的调用 next() 方法。当 StopIteration 异常被抛出时,循环会自动终止。 复制代码 代码如下: var it = Iterator(lang); for (var pair in it) print(pair); //每次输出 it 中的一个 [key, value] 键值对
如果你只想迭代对象的 key 值,可以往 Iterator() 函数中传入第二个参数,值为 true: 复制代码 代码如下: var it = Iterator(lang, true); for (var key in it) print(key); //每次输出 key 值
使用 Iterator() 访问对象的一个好处是,被添加到 Object.prototype 的自定义属性不会被包含在序列对象中。 Iterator() 同样可以被作用在数组上: 复制代码 代码如下: var langs = ["JavaScript", "Python", "Haskell"]; var it = Iterator(langs); for (var pair in it) print(pair); //每次迭代输出 [index, language] 键值对
就像遍历对象一样,把 true 当做第二个参数传入遍历的结果将会是数组索引: 复制代码 代码如下: var langs = ["JavaScript", "Python", "Haskell"]; var it = Iterator(langs, true); for (var i in it) print(i); //输出 0,然后是 1,然后是 2
使用 let 关键字可以在循环内部分别分配索引和值给块变量,还可以解构赋值(Destructuring Assignment): 复制代码 代码如下: var langs = ["JavaScript", "Python", "Haskell"]; var it = Iterators(langs); for (let [i, lang] in it) print(i + ": " + lang); //输出 "0: JavaScript" 等
我们的 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; }
生成器函数可以被一个类直接的当做 __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; } }