Recursion is a very confusing topic for beginners. Heck, a lot of experienced programmers aren’t very comfortable with them, including me. Keep in mind that most programmers (especially web developers) don’t have to deal with recursion much. But with certain types of data, it can be very useful and it does come up on interviews so it is good to know.
I think it is helpful to understand the call stack. When a function call is made, the information about the function call is “pushed” onto the call stack and when the function is complete, it is “popped” off the call stack.
Let’s look at our recursive function.
First we call it with
countdown(15)
Since n<1
is false, we go to the else
branch. There we have:
const COUNT_ARRAY = countdown(n - 1);
JS wants to figure out what goes into COUNT_ARRAY so it has to evaluate the right side of that equation. But that is countdown(n - 1)
, which is basically countdown(14)
The current function call (where n=15) can’t complete until this new function call (where n=14) is run and returns something. So, we leave that old function call (n=15) on the call stack (incomplete) and push a new function call on the call stack, the one where n=14. It will run into the same problem. So will n=13, etc.
By the time we get down to n=0, we have 15 incomplete function calls stacked up in the call stack, plus the current one that is running (n=0). When we get to n=0, finally n<1
is true. In recursion, we call this the base condition. Now, finally one of the function calls will finish, will return something. This function call finishes and returns []
. That function call has finished so it gets popped off the call stack and control returns to the next one on top of the call stack, the n=1 function call.
Now that we’re in the n=1 call, we can finally evaluate
const COUNT_ARRAY = countdown(n - 1);
because that call (countdown(0)
) returned an empty array, that’s what COUNT_ARRAY becomes. Then we unshift n (which is 1) onto it, so it is now [1]
, which we return that to the next incomplete function call on the call stack.
That is the n=2 call. It goes through the exact same process as the n=1 call, but because [1]
got returned, it is assigned to COUNT_ARRAY. Then we unshift n onto it, which is 2. So, we end up with [2, 1]
and return that to the next incomplete function call on the call stack.
This continues until all the function calls are “unwound” and we end up with our final result. The weird thing to grasp is that all those function calls are incomplete until we finally reach n=0 and then the whole thing unravels giving us our answer.
I think understanding recursion can be a visual thing. I might suggest checking out some videos.
Again, don’t worry too much if this is confusing. This may be something that takes some time to get a complete understanding. Perhaps consider settling for a partial understanding and work on other things and come back to this from time to time as your understanding grows.