2014-10-30 4 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; 
    } 
    } 
} 

Но это не работает. Я не знаю, как настроить его для запуска if/else для первых двух чисел в последовательности fib, а затем выполнить цикл while один раз для каждого последующего вызова.

+2

Знаете ли вы, что означает 'yield'? – ncksllvn

+0

Я думаю, что это похоже на возврат, который только приостанавливает функцию, а не завершает ее после возвращения значения – user137717

+2

Если это задание/домашнее задание (из «* Я получил прототип функции *»), то похоже, что вы чтобы узнать о закрытии. Не записывайте генераторы с 'yield'. – Bergi

ответ

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

как состояние фибра сохраняется между вызовами? Почему не удаляется вся эта информация при возврате функции? – user137717

+1

JS - напуганный язык, если вы исходите из фона Java. Это займет некоторое время, но вам нужно понять, как я связан с JS-закрытием. – ncksllvn

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

Обратите внимание, что деструктурирующий назначение var [prev, current] = поддерживается в FF и Traceur, но не в 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 (без флага) –

+0

@JanDvorak http://kangax.github.io/compat-table/es6/#Generators (yield) – Paul

+0

Будет ли редактировать пост с примечанием о назначениях деструктурирования. –

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 
Смежные вопросы