ECMAScript 6 引入了生成器、迭代器和迭代语法糖。 Node.JS v0.11.4 带有标志
--harmony --use_strict --harmony_generators
理解以下生成器
function* fibonacci() {
let previous = 0;
let current = 1;
while(true) {
let temp = previous;
previous = current;
yield current = temp + current;
}
}
然后我可以打印小于 1000 的斐波那契数。
for(let value of fibonacci()) {
if(value > 1000) { break; }
console.log(value);
}
对于本例,使用
while
循环代替 for
循环会更自然,类似于
while(value of fibonacci() < 1000) {
console.log(value);
}
迭代器的迭代可以使用
while
循环而不是 for
循环来完成吗?
您可以使用
next
函数逐步调用生成器
var sequence = fibonacci();
var value;
while ((value = sequence.next()) < 1000) {
console.log(value);
}
另外,也许更好的解决方案是这样的:
function* fibonacci(limit){
let previous = 0;
let current = 1;
while(previous + current < limit) {
let temp = previous;
previous = current;
yield current = temp + current;
}
}
for(let value of fibonacci(1000)) {
console.log(value);
}
考虑到支持此行为的其他语言,我有两种可能的方法:
1)一个使用 Harmony 代理,它可以让你做元表(有点像lua)并允许惰性迭代。这将提供以下符号:
var arr = ...; // create the resource
for(var i=0;arr[i]<1000;i++){
arr[i]; // consume fibonacci numbers
}
2) 第二个使用
take
函数,让您可以使用 .forEach
来使用可迭代对象,就像在 C# 或 python 中一样。这将允许以下符号:
takeWhile(fibGenerator,(item) => item<1000).forEach(... // consume with predicate
注意...
for of
循环遍历对象。它根本不保证顺序。但是,您可以执行以下操作来获得惰性迭代的概念。
您必须使用
--harmony_generators
和 --harmony_proxies
标志运行节点:
var arr = ...; // create an array and proxy it, use a generator internally
arr[50]; // will calculate the 50th fibonacci element and return it.
arr[100];// will calculate the 100th fibonacci element and return it.
for(var i=0;arr[i]<1000;i++){
arr[i];//the i-th fibonacci number
}
它只会计算尚未获取的数字,这将允许您使用简单的
for
循环。
方法如下*:
var cache = [];
var handler = {
get: (function(){
function fibIterator(){
var t=0,a=0,b=0;
return function(){
t=a;
a+=b;
b=t;
return a;
}
}
var iterator = fibIterator();
return function (target, fibNumber) {
if (name in cache) {
return cache[name];
}
while(iterator < fibNumber){
// update indexes.
}
})()
}
};
var arr = Proxy.create(handler);
(只是不要指望它会很快)
*(使用旧的代理表示法,因为节点尚不支持新的代理表示法,一旦获得支持就会更新)
旁注,在 JavaScript 中,由于函数可以通过闭包拥有内部状态,所以你甚至不需要生成器
Take
函数。对于此用例,您通常会使用 C# 等语言执行此操作。
function takeWhile(generating, predicate){
var res = [],last;
do{
res.push(last=generating())
}while(predicate(last));
return res;
}
然后做类似的事情
var res = takeWhile(fibIterator,function(item){
return item<1000;
});
res.forEach(function(){ ...
或按计数:
function take(generating,numToTake){
var res = [],num;
do{
res.push(last=generating())
}while(num++ < numToTake);
return res;
}
var res = take(fibIterator,1000);//first 1000 numbers
function *bar(){
yield 1;
yield 2;
yield 3;
return 4;
}
var value,
g = bar();
while((value = g.next()).value){
console.log(value);
}
//Object {value: 1, done: false}
//Object {value: 2, done: false}
//Object {value: 3, done: false}
//Object {value: 4, done: true}
是的,可以通过使用常规生成器方法来做到这一点。
var fib = fibonacci(), value;
while( (value = fib.next()) < 1000 ) {
console.log(value);
}
虽然我似乎更喜欢
for...of
语句,它负责处理下一个调用并处理 StopIteration
(如果序列是有限的)。
对于您的具体示例,如果您想在给定迭代次数后停止迭代,您现在可以使用 ECMAScript 2025
take
方法:
function* fibonacci() {
let previous = 0, current = 1;
while (true) {
yield previous; // Note that Fibonacci sequence starts with 0, 1, 1, 2,...
[previous, current] = [current, previous + current];
}
}
for (const value of fibonacci().take(20)) { // <-- limit iterations
console.log(value);
}