2014-10-30 58 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