How is this recursion working? - javascript

Now i was reading at MDN functions section, and i was reading this example about recursion, which was:
function foo(i) {
if (i < 0) //1
return;
console.log('begin:' + i); //2
foo(i - 1); //3
console.log('end:' + i); //4
}
foo(3);
So what I would normally expect of calling the recursive function foo with an argument of 3 is that it goes to line 1 checks that condition which is at the beginning not gonna hold so it continues to line 2 and logs the ("begin: 3") then it goes to line 3 where recursion happens and that will make it go back to the line 1 and go through the same flow of processes, which should lead to ("begin: 2"), ("begin: 1"), ("begin: 0"), then it should stop so that it won't clog ("begin: -1"), that indeed happens in MDN example but somehow it logs is one more time but reversibly like this:
// Output:
// begin:3
// begin:2
// begin:1
// begin:0
// end:0
// end:1
// end:2
// end:3
My Questions:
in which sense after that (i = -1) and the function returns, the
function is not exiting the function and continue to line number 4?
how is (i) increasing again, i see no loop or recursion that is
increasing the value of (i) again so that it logging again from 0 to 3??

Here is what is happenning in your case :
// foo(3) called
console.log('begin:3');
foo(2)
console.log('begin:2');
foo(1)
console.log('begin:1');
foo(0)
console.log('begin:0');
foo(-1)
return;
console.log('end:0');
console.log('end:1');
console.log('end:2');
console.log('end:3');
1) When you have (i == -1), the function is actually exiting with the return, but then keep executing the code in the parents functions (see point 2) )
2) When you call foo(-1), you call return, so it means that you get back to your parent caller and keep executing the following code.

your function doesn't terminate before the result of the inner function call is there.
1) is the abort condition, it tells the function when to stop
2) its not increasing, its going further, because the result of the foo(i-1) call is there

Whenever a recursion occurs, the control perpetually remains at the top level. So although, the function goes through n number of inner levels, a return statement from one of the inner called functions would merely return to its immediate parent level.
In this case: i=3 was at the top level, then 2 and then 1 and then 0. As the return was fired at i=-1, it was bubbled back to its parent 0 level. The next return bubbled it up to its parent i=2 , and then i=3.
Do mark as answer if you're satisfied.

Your function does exactly what you have told it to do:
print begin:3
do everything that foo(3-1) does
print end:3
Every call to a function wait for it to finish before resuming to the next line. If it's the same function it's the same. The version of the function that calls is not intervened with the one it calls so they are separate as if they were separate functions
Imagine this function:
function foo(i) {
console.log('begin:' + i); //1
console.log('end:' + i); //2
}
Now the first console.log might be a recursive function. You don't know and shouldn't have to know. It does it's job and returns. You don't question why it continues to line 2 so I guess you give recursive function more mystery than it deserves.

function foo(i) {
if (i < 0){ //1
return;
}
console.log('begin:' + i); //2
function foo(i-1) {
if (i-1 < 0){ //3.3.1
return;
}
console.log('begin:' + i-1-1); //3.3.2
function foo(i-1-1) {
if (i-1-1 < 0){ //3.3.1
return;
}
console.log('begin:' + i-1-1); //3.3.2
function foo(((i-1) - 1)-1){}; //3.3.3
console.log('end:' + i-1-1); //3.3.4
}
console.log('end:' + i-1); //3.4
}
console.log('end:' + i); //4
}
foo(3)
Let's pretend i is alwyas 3!
This is what happens:
going into //2 and log 3
going into //3.2 and log 2
going into //3.3.2 and log 1
going into //3.3.3 and do the same stuff and log 0
going into imaginary //3.3.3.4 and log 0 because the parameter of //3.3.3 is 0
going into 3.3.4 and log 1
going into 3.4 and log 2
going into 4 and log 3

Related

Why does setTimeout only print once in a loop?

From this document, I understand that setTimeout returns an ID value of the timer.
But when I run this code:
for (var i = 1; i <= 5; i++) {
setTimeout(function() { console.log('hello'); }, 100);
}
I get the following in the console tab:
i.e. It printed the timer ID once and then 5 consecutive 'hello' instances.
Shouldn't the output have timerID, hello, timerID, hello, .... instead?
Why does setTimeout only print its ID once even if it is in the loop?
What you're seeing is due to the REPL (Read-Eval-Print Loop) nature of the Javascript console.
You're expecting to see the result of all the setTimeout() calls from each iteration of the loop. However, after finishing a set of statements, the JS console only prints out the return value of the most recently executed statement.
A simple display of this behavior:
Note: In these examples I'm depicting the JS console input/output instead of including executable code blocks, since the behavior being discussed is specific to interactively using the console.
> x = 4;
<- 4
> y = 5;
<- 5
> x; y;
<- 5
In the last command there are two statements, only the value of the last is printed.
If you want to print out the id's of each setTimeout() call, you just have to explicitly perform the logging action:
> for (var i = 1; i <= 5; i++) {
console.log(setTimeout(function() { console.log('hello'); }, 100));
}
596
597
598
599
600
<- undefined
5 hello
Above you see:
the 5 outputs from the immediately executed console.log(setTimeout(...)) statements
the undefined return value of the last console.log(setTimeout(...)) statement
the grouped output from the 5 delayed console.log('hello') statements
The reason why this is happening is because synchronous code. When you run the for loop, it is executing the setTimeout() 5 times and so you get the ID, and after 0.1 seconds (100 MS) it then executes its code. If you want to get it how you predicted (ID "Hello" ID "Hello" ... ) you would have to use await and an asynchronous function.
The function setTimeOut returns a value, so it is not displayed in the console, unless you assign a variable to it and then output the variable.
for (var i = 1; i <= 5; i++) {
let delay = setTimeout(function() { console.log(delay,'hello'); }, 100);
}

What is the logic behind this double function call with recursion?

Where I currently have the console logs, countdown seems to count down from 10 to 1 (this makes sense) but then after this, way seems to add 15 to the final result of countdown 9 times, but for this to happen, I'd imagine that after each countdown loop, way is called, but that each keeps track of its own value? Any clarification about the Why and When of this logic would be helpful - Thanks!
var countdown = function(value) {
value = value - 1;
if (value == 0) {
return value;
}
console.log("loop 1 " + value);
return way(countdown(value));
};
function way(value) {
value = value + 15;
console.log(value);
return value;
}
countdown(10);
As commented above value is a local variable in either function and thus always bound to the scope of either function. It doesn't actually contribute to confusion aside from expecting too much complexity there. ;)
The behaviour arises from countdown() being called recursively and calling way() has to wait until recursive calls for countdown() are returning. But that's not happening until countdown()'s recursion has stopped at value 0 to be returned eventually. After that countdown() isn't invoked ever again, but since countdown() was invoked recursively and this is bubbling up through all invocations of countdown() there are multiple calls for way() with the result returned from the countdown() called at end which in turn was calling way() with result of countdown() etc. ... ok, got a bit confused here myself.
Since value isn't required to be that complex it might help to eliminate it for reducing code:
function countdown(value) {
if ( value == 1 ) { return 0; } // bail out condition
console.log("loop 1 " + value)
return way( countdown( value - 1 ) );
};
function way( value ) {
console.log(value);
return value + 15;
}
countdown(10);
way() is of no relevance to the recursion and thus might be substituted:
function countdown(value) {
if ( value == 1 ) { return 0; } // bail out condition
console.log("loop 1 " + value)
return countdown( value - 1 ) + 15;
};
countdown(10);
Due to recursion this code is diving into stack 9 frames deep. And then it is bubbling up stack returning the result of every passed frame increased by another 15 prior to bubbling up further on.
So actually, there is only one recursion.
At first, the code starts executing your first call to countdown with argument value=10
Stack: []
Execute countdown(10)
Stack: [countdown(10)]
Then execute way(countdown(9)), and to execute this, JS first evaluates countdown(9)
Stack: [countdown(10), countdown(9), ] and so on, you can imagine, until you reach countdown(0), then start popping out from the stack call.
First stack call resolved, countdown(0) = 0, then call way(0), the console logs 0+15, then countdown(0) eventually returns 15, then pop from stack countdown(1) which is equal to way(countdown(0)), which is way(15), then prints out 30, and so on...
Hope this is clear enough
In order to understand this recursive code, it's easiest to follow the program counter:
function way (value) {
value=value +15
console.log(value)
return value
}
countdown = function(value) {
value = value-1
if (value == 0) {
return value;
}
console.log("loop 1 " + value)
return way(
countdown(value));
};
countdown(10);
Start countdown with 10
value > 0 so run way(countdown(9)) //note: countdown is executed first.
Countdown runs with 9
value > 0 so run way(countdown(8)) //note: countdown is executed first.
...
...
...
value == 0, return 0 (in countdown): execute way
way returns 0 + 15
way returns 15 + 15
way .... etc.
As fora clarification why this logic would be helpful; I think there is a lesson to be learned here.
Basically there are 2 relevant function-call positions when applying recursion:
positioned before recursive call
positioned after recursive call
I will leave it as an exercise of why this has any relevance.

How does this recursive function resolve and why does it output what it does

I found myself unable to understand this example of a recursive function:
function foo(i) {
if (i < 0)
return;
console.log('begin:' + i);
foo(i - 1);
console.log('end:' + i);
}
foo(3);
The output is:
begin:3
begin:2
begin:1
begin:0
end:0
end:1
end:2
end:3
I understand how normal and nested functions work, and I think the return; here is supposed to exit the function when i gets lower than 0, so when i = -1, the first console.log() didn't show, but why after foo(-1 - 1) we get the output end:0 ?
To understand you must visualize the stack. Let me take you through the execution process:
We start by calling foo(3), so i is 3. Since i is not less than 0, log begin:3. Call foo(2)
i is now 2. Since i is not less than 0, log begin:2. Call foo(1)
i is now 1. Since i is not less than 0, log begin:1. Call foo(0)
i is now 0. Since i is not less than 0, log begin:0. Call foo(-1)
i is now -1. Since i is less than 0, we return and go up the stack. Continue from where we left off, the second log in foo(0):
console.log('end:' + i);
end:0 is logged because i is equal to 0. foo(0) has resolved, go up the stack to foo(1)
Continue from the second log in foo(1). end:1 is logged because i is equal to 1. foo(1) has resolved, go up the stack to foo(2)
Continue from the second log in foo(2). end:2 is logged because i is equal to 2. foo(2) has resolved, go up the stack to foo(3).
Continue from the second log in foo(3). end:3 is logged because i is equal to 3. foo(3) has resolved and thus the call is completely resolved.
This will yield:
begin:3 //Step 1
begin:2 //Step 2
begin:1 //Step 3
begin:0 //Step 4
end:0 //Step 5
end:1 //Step 6
end:2 //Step 7
end:3 //Step 8
Now, to answer the question:
but why after foo(-1 - 1) we get the output end:0 ?
We never call foo(-1 - 1) because foo(-1) returns immediately - it's the base case. The reason it starts logging end:i where i is ascending is because execution continues where it left off before you recursed and called foo(i - 1). Consequently, it logs end:i and then calls are resolved.
In fact, the function do stop when i=0 but since foo(i-1) is called before console.log('end:' + i); the output of all the console.log('begin:' + i); are displayed before the end are displayed with the i value.
Indeed, what really happens here is:
foo(3)
i=3 --> display : "begin 3";
Call foo(2)
i=2 --> display : "begin 2";
Call foo(1)
i = 1 --> display : "begin 1";
Call foo(0)
i = 0 --> display : "begin 0";
Call foo(-1) --> return
Go back to foo(0), display "end 0"
End of foo(0)
Go back to foo(1), display "end 1"
End of foo(1) ...
And so on.
this really helped me out. hope it helps someone out..
function foo(i) {
console.log(i, 'called');
if (i < 0) {
return `${i} is returning`;
} else {
console.log('continue');
}
console.log('begin:' + i);
const value = foo(i - 1);
console.log(value);
console.log(i, 'returned');
console.log('end:' + i);
}
foo(3);
every step along the way gets put in a queue [3,2,1,0] so when the program returns or exits with -1 and is able to run end it starts going back up the queue and letting the queue close or end. I tried my best to explain... My big Bro helped me out.. :)

why output this result when I make break to label in iteration?

I'm a newbie of javascript, and I certainly coundn't understand this output when I learn for statement..
foo: for(var i=0; i<3; i++){
console.log(i);
if(i==1){
break foo;
}
}
and I get some print like this..
0
1
to be honest, I dont know what happend here, I think that may throw error here because too deep iteration may be caused..
I want to get this result actually
0
1
0
1
0
1
...
maybe it's a stupid question, but I indeed want to get answer.
could anybody help me..
for(var i=0; i<3; i++){
console.log(i);
if(i==1){
break foo;
}
}
You are running a for loop which is iterating from 0 to 3 (excluded).
in each iteration it print the value of i.
if value of i is 1 then it break from loop
first iteration: i=0; print 0 continue as 0 != 1
second iteration: i=1 print 1 break as 1 == 1
lean more about for loop
Your loop is trying to output i while it is less than 3 and increment it by one for every iteration.
the if (i == 1) statement is true in the second iteration so the break gets executed which "exits" the loop.
An infinite loop will do it.
var v = 0;
while (true) { // <-- this runs forever!
console.log(v);
v ^= 1;
}
or with a limit of 1000 loops
var v = 1000;
while (v) {
out(v % 2);
v--;
}
// just for dispaying the result
function out(s) {
var descriptionNode = document.createElement('div');
descriptionNode.innerHTML = s + '<br>';
document.getElementById('out').appendChild(descriptionNode);
}
<div id="out"></div>
Actually break statement is used to get out of the loop.
As we know earlier for loop loops execution until condition (here i<3) is true. if the condition gets false then it terminates ie., when the i is incremented to 3.
But, the if condition to be checked is i==1 so whenever i is incremented to 1 the for loop gets terminated by break statement.
Each time the incremented value of i is printed in the console of the browser as a log. until the termination.
Your code does:
print i
then break
it will print 0 1 and then break the loop.

JavaScript Higher Order Function loop/recursion/confusion

Implement a function that takes a function as its first argument, a number num as its second argument, then executes the passed in function num times.
function repeat(operation, num) {
var num_array = new Array(num);
for(var i = 0; i < num_array.length; i++){
return operation(num);
}
}
//
// The next lines are from a CLI, I did not make it.
//
// Do not remove the line below
module.exports = repeat
RESULTS:
ACTUAL EXPECTED
------ --------
"Called function 1 times." "Called function 1 times."
"" != "Called function 2 times."
null != ""
# FAIL
Why doesn't this work?
I am assuming that I am starting a function called repeat. Repeat has two parameters and takes two arguments.
For the loop I create an array which has a length which is equal to the num passed in.
I then start a for loop, setting a counter variable i to 0. Then I set a conditional which states that i should always be less than the length of the num_array which was created earlier. Then the counter i is incremented up by one using the ++.
For every time that the conditional is true, we should return the value of calling running the function operation and passing the num as an argument.
The last two lines allow for easy running of the program through command line with pre programmed arguments being used.
Thank you for your time!
The return statement is breaking out of the function on the first iteration of the loop. You need to remove the return, and just call the function like this:
function repeat(operation, num) {
for(var i = 0; i < num; i++){
operation(num);
}
}
Note that I have removed the creation and iteration of the array, you do not need it for what you are doing here.
Also your initial question does not specify that you need to pass num to the function (but you do list it in your steps below), so you may be able to just do operation() instead of operation(num).
You probably want something like the below, rather than returning the result of the function operation(num) you want to store the value in teh array. return in a loop breaks out of the loop, so it would always only run once..
function repeat(operation, num) {
var num_array = new Array(num);
for(var i = 0; i < num_array.length; i++){
num_array[i] = operation(num);
}
}
//
// The next lines are from a CLI, I did not make it.
//
// Do not remove the line below
module.exports = repeat
If you are asking why the loop is not running, it's because you have to run the function after defining it (I'm assuming you are not already calling the function somewhere else).
Once calling the function repeat you will see that it is exiting after one iteration. This is because you are returning the operation - returning causes the function to end. To stay in the loop you just need to call operation(), without the return.
Also you don't need to create an array, you can just use the counter you are defining in the for loop.
So the code would look something like this:
var op = function(arg) {console.log(arg);},
n = 5;
function repeat(operation, num) {
for(var i = 0; i < num; i++){
operation(i);
}
}
repeat(op ,n);
// The next lines are from a CLI, I did not make it.
//
// Do not remove the line below
module.exports = repeat

Categories