【问题标题】:function generator javascript函数生成器 javascript
【发布时间】:2014-10-30 04:32:48
【问题描述】:

我需要制作一个迭代无限序列的函数生成器,比如斐波那契数列。它应该在调用时返回序列中的下一个值。我得到了一个函数原型:

function genfib() {
  return function fib() {
  }
}

应该这样使用:

var fib = genfib();
fib(); // -> returns 0
fib(); // -> returns 1
fib(); // -> returns 1
fib(); // -> returns 2

每次调用fib() 时,我都对正在执行的操作感到困惑。我试图做类似的事情

function genfib() {
  var count = 1;
  if (count === 1) {
    count++;
    yield 0;
  }
  else if (count === 2) {
    count++;
    yield 1;
  }
  var a = 0;
  var b = 1;
  return function fib() {
    while(1) {
      count = a + b;
      a = b;
      b = count;
      yield count;
    }
  }
}

但它不起作用。我不知道如何设置它来为fib 序列中的前两个数字运行if/else,然后为每个后续调用运行一次while 循环。

【问题讨论】:

  • 你知道yield是做什么的吗?
  • 我认为这有点像 return 只是暂停一个函数而不是在返回一个值后终止它
  • 如果这是一个作业/家庭作业(来自“我得到了一个函数原型”),那么看起来你应该学习闭包。不要用yield 编写生成器。
  • 如果我们的回答对您有所帮助,请将其中一个答案标记为正确。
  • @user137717: 差不多 :) 但是是的,该方法存根是使用闭包的明确提示。

标签: javascript generator


【解决方案1】:

如果你想使用 ES6 生成器和yield,那么方法如下:

function *fibonacci() {
    var [prev, current] = [0, 1];

    while (true) {
        [prev, current] = [current, current+prev];
        yield current;
    }
}

迭代结果的一种方法是使用for-of 循环:

for (var v of fibonacci()) {
    console.log(v);
    if (v > 100) break;
}

请注意,FF 和 Traceur 支持解构赋值 var [prev, current] =,但目前 Chrome 或 node 不支持。如有必要,将其重写为:

function *fibonacci() {
    var prev = 0, current = 1, oldprev;

    while (true) {
        oldprev = prev;
        prev = current;
        yield current += oldprev;
    }
}

如果你想要你得到的函数原型的语义,那么:

function genfib() {
    var iterator = fibonacci();
    return function fib() {
        return iterator.next().value;
    };
}

【讨论】:

  • "var [prev, current]" - 这真的有效吗?从何时起?我不认为它在 ES5 中,Chrome 还不支持 ES6(没有标志)
  • 这是一个非常酷的答案 - 只是不想切换浏览器或启动服务器来运行它:)
  • 如果这是一个家庭作业,那么 OP 看起来就像一个忍者一样。
【解决方案2】:

如果你问我,yield 在这个函数中没有位置,只是巧妙地使用了 JavaScript closure。

一开始你的想法是对的——你确实需要一个返回函数的函数。在内部函数之外有几个变量——一个用于旧的,一个用于下一个。在函数内部,您所要做的就是计算新的next 值,然后将old 设置为next 的先前值。要切换它们的值,您需要一个占位符变量。

function genfib() {
  var next = 1
  var old = 0
  return function fib() {
    var newNext= next + old
    old = next
    next = newNext
    return next
  }
}

var fib = genfib()

var result = []

for ( var i = 0; i < 10; i++ )
  result.push( fib() )

document.body.innerHTML = result.join()

当然,这不考虑第一次函数调用,这是一种特殊情况(1 应该返回两次。)但我会让你弄清楚:-)

【讨论】:

  • 如何在调用之间保留 fib 的状态?为什么当函数返回时所有这些信息都没有被删除?
  • 如果你有 Java 背景,JS 是一门时髦的语言。这需要一些时间,但你必须掌握我链接到的 JS 闭包。
【解决方案3】:
function* fib(num) {
  var a = num, b = a + 1, c = a;

  while (true) {
    yield a;
    c = a;
    a = b;
    b = c + b;
  }
}

var it = fib(0);
console.log(it.next().value); // 0
console.log(it.next().value); // 1
console.log(it.next().value); // 1
console.log(it.next().value); // 2
console.log(it.next().value); // 3
console.log(it.next().value); // 5
console.log(it.next().value); // 8
console.log(it.next().value); // 13

有关如何使用生成器的高级概述,checkout this post。

【讨论】:

    【解决方案4】:
    function* fibonacci(){
      var fn1 = 1;
      var fn2 = 1;
      while (true){  
        var current = fn2;
        fn2 = fn1;
        fn1 = fn1 + current;
        var reset = yield current;
        if (reset){
            fn1 = 1;
            fn2 = 1;
        }
      }
    }
    
    var sequence = fibonacci();
    console.log(sequence.next().value);     // 1
    console.log(sequence.next().value);     // 1
    console.log(sequence.next().value);     // 2
    console.log(sequence.next().value);     // 3
    console.log(sequence.next().value);     // 5
    console.log(sequence.next().value);     // 8
    console.log(sequence.next().value);     // 13
    console.log(sequence.next(true).value); // 1
    console.log(sequence.next().value);     // 1
    console.log(sequence.next().value);     // 2
    console.log(sequence.next().value);     // 3
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-08-02
      • 1970-01-01
      • 2016-04-08
      • 2018-01-30
      • 2019-06-11
      • 1970-01-01
      • 1970-01-01
      • 2017-01-17
      相关资源
      最近更新 更多