在前一篇翻译的文章中,我们描述关于generator的使用,这里我们主要讨论的是迭代器的话题,以及迭代器是如何与generator关联的并且用generator来生成值的。
想一想现在有这么一个需求,它要求生成一系列的数字,并且每个数字都与前一个数字有一个定义好的内在关系。
首先我们可以直接用闭包实现这个功能。
这里需要注意的一点是这样的设计存在内存泄露的隐患。具体可以参见(http://www.ibm.com/developerworks/cn/web/wa-jsmemory/)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
接下来我们看看通过迭代器接口的实现:
next()的调用会返回两个属性的对象:done是布尔值类型标记迭代器的完成状态。value持有迭代值。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
ES6加入了for .. of的循环,这意味着便准的迭代器可以使用原生的loop循环。
这里需要注意的是,因为前面定义的迭代器接口会始终返回done:false,所以for loop会永远的循环下去,这就是为什么在这里加入了break条件。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: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函数构建一个迭代器。
下面是手动调用的例子
重点来了,generator的迭代器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可以被看作为producer of values, 通过迭代器接口的next方法抽取值。
generator本身并不是迭代对象,虽然看起来很相似,执行generator,得到一个迭代器。
现在用一个generator来实现一个生成无限数字序列的函数function
*
foo
(){
..
}
var
it
=
foo
();
这里,只要我们请求something, while loop告诉我们generator会一直在运行去生成新的值,function
*
something
()
{
var
nextVal
;
while
(
true
)
{
if
(
nextVal
===
undefined
)
{
nextVal
=
1
;
}
else
{
nextVal
=
(
3
*
nextVal
)
+
6
;
}
yield
nextVal
;
}
}