Я относительно новичок в 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
и завершает программу.
У меня есть интуиция, что это может быть глупый вопрос, но я все еще хочу знать, чего мне не хватает. Помощь будет оценена по достоинству
Рекурсия строит стек, так что: первый пришел, последний вышел. Поскольку первый оператор печати появляется перед рекурсией, вы двигаетесь вниз. Наоборот, последнее происходит после, поэтому вы двигаетесь обратно вверх... Думайте о сообщении «конец» как об условии очистки после того, как вы достигнете нуля,
Узнайте, как использовать точки останова и шаг, а также отлаживать собственный поток кода.
i
не уменьшается, значение i-1
передается как значение при рекурсивном вызове foo
. Когда значение, переданное в foo
, равно -1, оно возвращается до того, как что-либо будет зарегистрировано в консоли, и поднимается на уровень, где i
равно 0.
console.info(`end: ${i}`);
выводит это значение, а затем функция неявно возвращается на следующий уровень, где i
равно 1. И так далее.
Но как рекурсивная функция вызывается после того, как return возвращает переход к следующей строке рекурсивной функции (т.е. после конца: 0)
@Shubham функция больше не вызывается, но каждый вызов функции должен завершить свой процесс.
Рад помочь, и теперь это имеет смысл.
Поток такой
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
.
Ничего не меняется.
Поток программы должен возвращаться к следующей строке после каждого вызова функции.