42

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吗?

4

4 回答 4

15

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);
}
于 2013-07-07T14:05:23.433 回答
7

考虑到支持这种行为的其他语言,我有两种可能的方式来解决这个问题:

1)一个使用 Harmony 代理,它可以让你做元表(有点像lua)并允许惰性迭代。这将提供以下符号:

var arr = ...; // create the resource
for(var i=0;arr[i]<1000;i++){
    arr[i]; // consume fibonacci numbers
}

2) 第二个使用一个函数,让您使用C#pythontake的可迭代对象。这将允许以下符号:.forEach

 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
于 2013-07-07T14:17:37.633 回答
1

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}
于 2016-02-03T16:45:48.397 回答
0

是的,可以通过使用常规生成器方法来做到这一点。

var fib = fibonacci(), value;
while( (value = fib.next()) < 1000 ) {
    console.log(value);
}

虽然我似乎更喜欢for...of处理那些下一个调用和处理StopIteration(如果序列是有限的)的语句。

于 2013-07-07T14:05:32.833 回答