iterator和generator之间的区别是啥

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iterator和generator之间的区别是啥相关的知识,希望对你有一定的参考价值。

    这个问题分类有误,应该标记为计算机、程序。

    引用一段大神的介绍:

迭代器EDIT

迭代器是一个对象,知道如何存取物品从一个集合一次取出一项, 而跟踪它的当前序列所在的位置。在  javascript 中 迭代器是一个对象,它提供了一个 next() 方法返回序列中的下一个项目。当这个序列消亡时这个方法可以随时抛出一个StopIteration exception(异常)。

一旦创建,迭代器对象可以显式地通过不断调用 next(),或隐式地使用 JavaScript 的 for...in  和 for each 构造。

简单的迭代器对象和数组可以使用 Iterator() 函数创建(下面是一个简单的对像):

var lang = name: 'JavaScript', birthYear: 1995 ;
var it = Iterator(lang);

一旦初始化,next()方法可以用来依次访问对象中的键-值:

var pair = it.next(); // Pair is ["name", "JavaScript"]
pair = it.next(); // Pair is ["birthYear", 1995]
pair = it.next(); // A StopIteration exception is thrown

一个 for...in 循环结构可以直接取代next()方法的调用。 当StopIteration exception异常抛出时这个循环会自动终止。

var it = Iterator(lang);
for (var pair in it)
 print(pair); // prints each [key, value] pair in turn

假如我们只想遍历一个对象的 keys 时,我们可以通过把第二个参数设置为 true 来实现:

var it = Iterator(lang, true);
for (var key in it)
 print(key); // prints each key in turn

使用 Iterator() 来访问对象内容的优点是对于那些已经加入对象的自定义属性(不用管属性名,一股脑的访问,或者只访问属性,上面就是这样)。它的原型不会包含在序列中。

Iterator() 也可以用于数组:

var langs = ['JavaScript', 'Python', 'C++'];
var it = Iterator(langs);
for (var pair in it)
 print(pair); // prints each [index, language] pair in turn

基于对象,通过传递true作为第二个参数,将会导致迭代结果发生数组索引上益(会吗?我也没搞明白,你知道的话请告诉我):

var langs = ['JavaScript', 'Python', 'C++'];
var it = Iterator(langs, true);
for (var i in it)
 print(i); // prints 0, then 1, then 2

也可以指定块作用域变量(let是个javascript1.7的关键字,可以使用 let 建立只存在于 for 循环上下文中的变量)包括索引和值(index and value)在for…in循环中使用let关键字和非结构化赋值:

var langs = ['JavaScript', 'Python', 'C++'];
var it = Iterator(langs);
for (let [i, lang] in it)
print(i + ': ' + lang); // prints "0: JavaScript" etc.

定义自定义迭代器EDIT

某些对象遍历集合的项目时应该使用特定的方式遍历。

遍历一个序列对象时应该是一个接着一个。

遍历一棵树时应该使用深度优先或者广度优先方式。

遍历一个数据库查询结果对象时应该是一条一条地遍历,即使整个结果并没有被加载到一个数组中。

一个迭代器在一个无限的数学序列(如斐波那契序列)应该能够一个一个地返回结果而不创建一个无限长度的数据结构。

JavaScript可以让你编写代码来表示自定义迭代逻辑并链接到一个对象。

我们来创建一个简单的序列对象用来存放low和high。

function Range(low, high)
 this.low = low;
 this.high = high;

现在我们要创建一个遍历器,可以返回这个序列中的一序列包容性的整数,这个遍历器接口要求我们我们实现一个next()方法,这个next()方法返回这个序列或者抛出一个StopIteration exception异常。

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被一个序列实例所序列化,并且维持它自己当前的属性属性所在位置。

最后,为了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); // prints 3, then 4, then 5 in sequence

生成器(Generators): 一个更好的方法来构建遍历器EDIT

虽然迭代器是一个有用的工具,但是由于需要显示地维持他们的内部状态,所以他们的构造需要仔细的规划(看得我眼花呀)。生成器给你提供了一个强大的选择:它允许你通过写一个可以保存自己状态的的简单函数来定义一个迭代算法。

一个生成器其实是一种特殊类型的函数(这个函数作为一个为迭代器工作的工厂),一个函数如果它里面包含了一个或一个以上的yield表达式,那么这个函数就成为一个生成器了。


Note: 这个yield关键字只能被包含在下面的代码快中才有用 <script type="application/javascript;version=1.7">  (或者更高版本).XUL脚本标记访问这些功能不需要这个特殊的块。


当一个生成器函数被一个函数体调用时并不会马上执行;相反,它会返回一个generator-iterator对象。每次调用generator-iterator的next()方法将会执行这个函数体至下一个yield表达式并且返回一个结果。当函数执行完或者执行到一个return时抛出一个StopIteration exception异常。

用一个案例来阐述:

function simpleGenerator()
 yield "first";
 yield "second";
 yield "third";
 for (var i = 0; i < 3; i++)
   yield i;


var g = simpleGenerator();
print(g.next()); // prints "first"
print(g.next()); // prints "second"
print(g.next()); // prints "third"
print(g.next()); // prints 0
print(g.next()); // prints 1
print(g.next()); // prints 2
print(g.next()); // StopIteration is thrown

一个生成器函数可以直接用作为一个类的__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); // prints 3, then 4, then 5 in sequence

并不是所有的生成器都会终止;它也可以创建一个无穷序列的生成器。下面实现了斐波纳契数列的生成器:

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

生成器可以有参数,但被限制在函数第一次调用时。生成器可以通过一个return语句来终止(因为他们将抛出一个topIteration exception)。下面是一个变异的fibonacci()函数有一个limit参数,一旦满足条件将终止。

function fibonacci(limit)
 var fn1 = 1;
 var fn2 = 1;
 while (1)
   var current = fn2;
   fn2 = fn1;
   fn1 = fn1 + current;
   if (limit && current > limit)
     return;
   yield current;
 

参考技术A generator是生成器,当然是用来生成某些东西。「generator」生成「Iterator对象」

以上是关于iterator和generator之间的区别是啥的主要内容,如果未能解决你的问题,请参考以下文章

Iterables vs. Iterators vs. Generators(可迭代对象,迭代器,生成器)

java中接口和类之间是啥关系?

RETURN_GENERATED_KEYS 和指定生成的列名之间的区别

python generator iterator和iterable object

迭代器,生成器(generator)和Promise的“微妙”关系

生成器和迭代(Generator: iterable , iterator, iteration)