2014-10-30 61 views
3

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

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循环。

+2

你知道'yield'的含义吗? – ncksllvn 2014-10-30 04:40:18

+0

我认为它有点像一个返回,只是暂停一个函数,而不是在返回值后终止它 – user137717 2014-10-30 04:42:24

+2

如果这是一个赋值/作业(从“*我给了一个函数原型*”),那么它看起来像你应该学习关闭。不要用'yield'来编写生成器。 – Bergi 2014-10-30 05:14:55

回答

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应被两次退回。)但是我把它留给你找出:-)

+0

如何在调用之间保留fib的状态?为什么函数返回时并不会删除所有这些信息? – user137717 2014-10-30 05:10:46

+1

如果你来自Java背景,JS是一种时髦的语言。这需要一些时间,但你必须掌握我链接到的JS封闭。 – ncksllvn 2014-10-30 05:11:44

7

如果你想使用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或节点。如果有必要把它改写为:

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; 
    }; 
} 
+0

“var [prev,current]” - 是否真的有效?从何时起?我不认为它是在ES5中,并且Chrome还不支持ES6(没有标志) – 2014-10-30 05:00:51

+0

@JanDvorak http://kangax.github.io/compat-table/es6/#Generators(yield) – Paul 2014-10-30 05:03:22

+0

将编辑帖子并附上关于解构任务的说明。 – 2014-10-30 05:06:26

1
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

0
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 
相关问题