Как получается, что параметр возвращается к своему предыдущему значению после возврата из рекурсивного вызова функции?

Я относительно новичок в JavaScript, и я не могу понять, как выполняется этот код.

function foo(i) {
  if (i < 0) {
    return;
  }
  console.info(`begin: ${i}`);
  foo(i - 1);
  console.info(`end: ${i}`);
}
foo(3);

вывод этого кода

begin: 3
begin: 2
begin: 1
begin: 0
end: 0
end: 1
end: 2
end: 3

Насколько я понимаю, после всех журналов оператора begin должен быть напечатан только один журнал с оператором end, который также имеет значение -1.

begin: 3
begin: 2
begin: 1
begin: 0
end: -1 

Когда я уменьшается с 0 на -1, условие оператора if становится истинным и возвращает поток к следующей строке рекурсивной функции, печатает end: -1 и завершает программу.
У меня есть интуиция, что это может быть глупый вопрос, но я все еще хочу знать, чего мне не хватает. Помощь будет оценена по достоинству

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

Teemu 13.04.2023 20:44

Рекурсия строит стек, так что: первый пришел, последний вышел. Поскольку первый оператор печати появляется перед рекурсией, вы двигаетесь вниз. Наоборот, последнее происходит после, поэтому вы двигаетесь обратно вверх... Думайте о сообщении «конец» как об условии очистки после того, как вы достигнете нуля,

Mr. Polywhirl 13.04.2023 21:04

Узнайте, как использовать точки останова и шаг, а также отлаживать собственный поток кода.

Roko C. Buljan 13.04.2023 21:33
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
3
73
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

i не уменьшается, значение i-1 передается как значение при рекурсивном вызове foo. Когда значение, переданное в foo, равно -1, оно возвращается до того, как что-либо будет зарегистрировано в консоли, и поднимается на уровень, где i равно 0.

console.info(`end: ${i}`); выводит это значение, а затем функция неявно возвращается на следующий уровень, где i равно 1. И так далее.

Но как рекурсивная функция вызывается после того, как return возвращает переход к следующей строке рекурсивной функции (т.е. после конца: 0)

Shubham 13.04.2023 20:58

@Shubham функция больше не вызывается, но каждый вызов функции должен завершить свой процесс.

sadsongco 14.04.2023 11:35

Рад помочь, и теперь это имеет смысл.

sadsongco 14.04.2023 20:19

Поток такой

   Foo(3)
      Begin 3
      Foo(2)
        Begin 2
        Foo(1)
          Begin 1
          Foo(0)
            Begin 0
            Foo(-1) returns
            End 0
          End 1
        End 2
      End 3
Ответ принят как подходящий

Когда вы вызываете функцию, вы не вводите определение этой функции. Вы вводите копию этого определения функции.

Каждый вызов функции является отдельным. Неважно, как называется эта функция. Будь то то же самое имя или какое-то другое имя - каждый вызов является новым. Он копирует соответствующее определение и работает с новой копией.

Представьте, что вы вызываете foo(1) в своем примере. Тогда ваш фрагмент такой же, как

function foo1(i1) { // i1 here is 1
  if (i1 < 0) {
    return;
  }
  console.info(`begin: ${i1}`);
  foo0(i1 - 1);
  console.info(`end: ${i1}`);
}
function foo0(i0) {  // i0 here is 0
  if (i0 < 0) {
    return;
  }
  console.info(`begin: ${i0}`);
  foo_1(i0 - 1);
  console.info(`end: ${i0}`);
}
function foo_1(i_1) {  // i_1 here is -1
  if (i_1 < 0) {
    return;        // return is called
  }
  console.info(`begin: ${i_1}`);   // these lines
  foo_2(i_1 - 1);                 // are not
  console.info(`end: ${i_1}`);     //   executed
}
foo1(1);

Вы, наверное, не удивлены, что эти i_nnn в этих разных функциях не мешают друг другу. Но это одно и то же, даже если вместо этих foo везде вызывается одна и та же функция foo_nnn. Потому что каждый вызов foo копирует одно и то же определение и работает с новой, свежей его копией, как если бы она получила новое имя foo_nnn, как здесь выше, работая со своим набором внутренних переменных i_nnn.

Поэтому неудивительно, что приведенное выше выполнение происходит как

foo1(1);

который

//foo1(1):
  ///// i1==1 ////
  if (i1 < 0) { return; }       // i1==1
  console.info(`begin: ${i1}`);  // i1==1
  foo0(i1 - 1);
  // function foo1 continues
  console.info(`end: ${i1}`);    // i1==1
  // end of function foo1

и это то же самое, что

//foo1(1):
  //// i1==1 ////
  if (i1 < 0) { return; }       // i1==1 ; 1<0 is false
  console.info(`begin: ${i1}`);  // i1==1
  //foo0(0):
          //// i0==0 ////
          if (i0 < 0) { return; }       // i0==0 ; 0<0 is false
          console.info(`begin: ${i0}`);  // i0==0
          foo_1(-1);
          // function foo0 continues
          console.info(`begin: ${i0}`);  // i0==0
          // end of function foo0
  // function foo1 continues
  console.info(`end: ${i1}`);    // i1==1
  // end of function foo1

и это то же самое, что

//foo1(1):
  //// i1==1 ////
  if (i1 < 0) { return; }       // i1==1 ; 1<0 is false
  console.info(`begin: ${i1}`);  // i1==1
  //foo0(0):
          //// i0==0 ////
          if (i0 < 0) { return; }       // i0==0 ; 0<0 is false
          console.info(`begin: ${i0}`);  // i0==0
          //foo_1(-1):
                  //// i_1== -1 ////
                  if (i_1 < 0) { return; }   // i_1== -1 ; -1<0 is true
                  // the function foo_1 is exited i.e.
                  //    nothing is printed and no more calls are made
                  // end of function foo_1
          // function foo0 continues
          console.info(`begin: ${i0}`);  // i0==0
          // end of function foo0
  // function foo1 continues
  console.info(`end: ${i1}`);    // i1==1
  // end of function foo1

Теперь замените все foo_nnn выше на foo.

Ничего не меняется.

Другие вопросы по теме