Javascript - почему моя функция рекурсивная? - PullRequest
0 голосов
/ 07 мая 2020

Я не знаю, где я ошибаюсь. Почему моя функция возобновляется? Ожидаю результат sum = 3;

function init() {
  let object = {
    firsNum: 1,
    sum: 0,
  };
  add(1, object.firsNum, fun);
  console.log(object.sum);
}

function fun(a) {
  a.firstNum++;
  a.sum += a.firsNum;
  fun(a);
}

function add(a, b, callback) {
  return callback(a + b);
}
init();

Ответы [ 3 ]

1 голос
/ 08 мая 2020

Я думаю, вы не полностью понимаете каждую концепцию программирования, которую вы использовали в своем коде.

Кроме того, ваш исходный код содержит опечатку: a.firstNum++; где он должен читать firsNum как в во всех остальных местах.

Давайте разберем ваш код на отдельные задачи.

Рекурсия

Рекурсия означает, что функция вызывает сама себя. Рекурсия - это один из способов вычисления, итерации или обхода данных. Другой - итерация с использованием циклов, таких как while или for.

Давайте посмотрим на этот упрощенный пример:

function recurse(counter) {
   console.log(counter);
   recurse(counter + 1);
}
recurse(0);

Это вызовет recurse() бесконечно, так как ничто не останавливается это называть себя. Рекурсия, как и итерация, требует некоторого условия остановки для прерывания рекурсии.

Если вы хотите остановиться на определенном значении, вам придется вызывать функцию только до тех пор, пока это условие не будет выполнено:

function recurse(counter) {
   console.log(counter);
   if (counter < 42) {
      recurse(counter + 1);
   }
}
recurse(0);

Это будет только рекурсивно и увеличиваться, пока не будет достигнуто 42.

Вы даже можете передать условие остановки с самой функцией:

function recurse(counter, maxValue) {
   console.log(counter);
   if (counter < maxValue) {
      recurse(counter + 1, maxValue); // maxValue gets passed along
   }
}
recurse(0, 42);

Чтобы ваша рекурсивная функция остановилась на определенное значение, которое вы должны добавить такое условие:

function fun(a) {
  a.firstNum++;
  a.sum += a.firstNum;
  if (a.sum < a.maxNum) {
    fun(a);
  }
}

Затем вам нужно будет убедиться, что ваш объект определяет условие:

let object = {
  maxNum: 3, // stop condition added
  firsNum: 1,
  sum: 0,
};

Хотя это само по себе выиграло ' t решить проблему. Продолжайте читать.

Обратные вызовы

Обратные вызовы - это функции, переданные как параметры функции, свойства объекта или элементы массива другим функциям.

Обратные вызовы позволяют вам решить, какую функцию вызывать во время время выполнения без необходимости реализовывать поведение ветвления с использованием операторов if или switch и требовать определенных имен функций на момент написания.

function someCallback() { /* ... */ }

function callTheCallback(callback) {
   callback(); // Execute the parameter as a function
}

callTheCallback(someCallback);

let someCallbackReference = someCallback;

// Call the same function but indirectly via a variable
callTheCallback(someCallbackReference);

В приведенном выше примере someCallback может косвенно происходить из другого объекта.

Вы даже можете напрямую указать выражение функции в качестве обратного вызова:

callTheCallback(function() {
   // ...
});

С обратными вызовами очень важно gr asp разница между передачей результата вызова функции и сама функция:

callTheCallback(someCallback); // Callback function passed
callTheCallback(someCallback()); // Result of a function call passed

Обратите внимание, что передача результата вызова функции может быть вполне допустимой, если возвращаемое значение само является функцией. Это также не редкость в программировании.

Обратные вызовы часто используются для инверсии управления (Io C) в целом и асинхронного программирования в частности.

Примеры функций обратного вызова:

В вашем случае fun() передается как обратный вызов третьего параметра в add().

Теперь, когда вы знаете, как использовать рекурсию и обратные вызовы, есть все еще semanti c ошибки в вашем коде ...

Семантические ошибки

В отличие от синтаксических ошибок (неправильная грамматика кода) семантические ошибки - это ошибки со смыслом кода.

Интерфейс add()

Анализируйте вашу функцию API :

function add(a, b, callback) {
  return /* some value - callback() call removed for simplicity */;
}

add() принимает три параметра и возвращает значение . Третий параметр называется «обратный вызов» и, следовательно, должен быть функцией.

Ваш вызов add() выглядит разумным, хотя вы не используете возвращаемое значение (что не обязательно является ошибкой).

add(1, object.firsNum, fun);

Реализация add()

Поскольку параметры add() не задокументированы, ваше намерение неоднозначно.

Имя вместе с тем, что там два параметра, a и b, приводят к предположению, что эти два значения должны быть сложены. И вы очень хорошо это делаете:

return callback(a + b);

Но! то, что вы передали как функцию обратного вызова - это fun() - ожидает другие параметры, а не число. fun() ожидает объект.

Правильно задокументированный, это будет выглядеть так:

/**
 * Recursively sum values until a maximum value is reached.
 * 
 * @param {Object} a object containing the sum, the increment and the max value
 * @param {Number} a.firsNum start value
 * @param {Number} a.maxNum the maxium value up to which to add "firsNum" to "sum"
 * @param {Number} a.sum the summed value, shall be 0 initially
 * @returns {undefined} nothing is returned
 */
function fun(a) {
  // ...
}

Приведенный выше стиль комментариев называется JsDo c: https://jsdoc.app

Обратите внимание на использование собственных имен для функций, переменных и параметров. Собственные имена помогают документировать код без написания явных комментариев к документации.

Исправление ошибки

Имея ограниченные знания о том, что вы действительно хотели достичь, можно только предполагать. Я предполагаю, что add(), хотя его имя и параметры выглядят разумно, реализован неправильно. Ваша проблема может быть решена путем правильного вызова обратного вызова (fun()):

function add(obj, callback) {
  return callback(obj);
}

И:

add(object, fun);

Поскольку нам нужен объект, add() теперь ожидает его как единый параметр.

Что ж, теперь это не имеет большого смысла. fun() может быть вызван непосредственно из init(), а не через ссылку обратного вызова, а add() имеет запутанное имя.

Я не буду дальше строить предположения о ваших намерениях и как реализовать альтернативные решения проблемы.

Что вы узнали

  • О Сеть разработчиков Mozilla
  • Как работает рекурсия
  • Функции могут быть переданы как параметры и назначены переменным или свойствам
  • Чтение кода
  • Преимущества документирования кода и правильного наименования функций и переменных
0 голосов
/ 08 мая 2020

Ваш код

function init() {
  let object = {
    firsNum: 1,
    sum: 0,
  };
  add(1, object.firsNum, fun);
  console.log(object.sum);
}

function fun(a) {
  a.firstNum++;
  a.sum += a.firsNum;
  fun(a);
}

function add(a, b, callback) {
  return callback(a + b);
}
init();

init

Определяет объект с атрибутами firsNum и sum, затем вызывает add, передавая 1, 1 и fun.

fun

Получает параметр. Увеличивает firstNum параметра и добавляет его к sum. Затем он вызывает себя .

add

Получает три параметра: a, b и callback. Вызывает callback и передает ему a + b.

Вызывается поток

init, затем он вызывает add и передает 1 a, 1 b и от fun до callback. В результате добавляются вызовы callback, что равно fun, и поскольку оба a и b равны 1, a + b = 2 передается в fun. fun увеличивает a.firstNum, что кажется ошибкой, поскольку a - это число, то к sum добавляется какое-то другое странное значение. Просто удалите fun(a); inside fun, чтобы избавиться от рекурсии, но это не единственная ошибка в вашем коде. Также убедитесь, что внутри fun.

есть инструкция return
0 голосов
/ 07 мая 2020

Только что закомментировал рекурсивный код

function init() {
            let object = {
                firsNum: 1,
                sum: 0,
            };
            add(1, object.firsNum, fun);
            console.log(object.sum);
        }

        function fun(a) {
            a.firstNum++;
            a.sum += a.firsNum;
            //fun(a);
        }

        function add(a, b, callback) {
            return callback(a + b);
        }
        init();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...