So recursion can be a very confusing topic. A function that calls itself, repeatedly? Doesn’t seem right somehow. But let’s see what we can do here.
First, defining recursion (not an official one, simply a definition in my own words): repeatedly performing some task until something tells us to stop. In a more formal definition, a recursive function is a function that repeatedly calls itself on some dataset, until some exit condition is met.
In this case, we have a dataset: [2,3,4,5]
. We want to act on some part of that dataset, until some exit condition happens. What is that exit condition? The if statement: if(n<=0)
. When that happens, we stop repeating the function call, and start returning stuff.
Let’s say we call your sum
function like this: sum([2,3,4,5], 3)
. We are setting its internal arguments like so: arr=[2,3,4,5]
and n=3
. So we create an executed function “scope” (think of it as a box containing the variables and evaluations for this particular function call).
Within that “box”, our n
is greater than 0, so we fall into the else
side of the statement. So we’ll be returning something, but what? We’ll be making another function scope (another box) within the current one, like so sum([2,3,4,5], 2)
, which will return some value eventually, and adding that to arr[2]
, which is 4
in that outermost function scope.
Now, we’ve got two nested “boxes”. The outermost box can be identified by n===3
, and the next one in is exactly the same except that n===2
. Well, 2 is still greater than zero - so we again fall into that else
branch, and create another function scope (another darn box!). We’re going to call the function sum([2,3,4,5], 1)
, add that to arr[1]
(which is 3
), and return that.
So at this point, we’ve “nested” three boxes:
- sum() with arr===[2,3,4,5] and n===3, which contains
- sum() with arr===[2,3,4,5] and n===2, which contains
- sum() with arr===[2,3,4,5] and n===1, which **still** isn't n<=0!
So our innermost “box” (again, function scope) needs to call sum([2,3,4,5], 0)
and add that to arr[0]
, which is 2. Our function has now called itself four times, and created four nested function boxes. But hey! n
is now less than or equal to zero!
This is key: we have reached our exit condition. When n<=0
, we stop calling the function (we stop creating nested boxes), and we simply return 0. Where are we returning that 0 to? To the next box out.
That next box (the one with n===1
) takes in that 0, and adds the thing found at arr[0]
to it. arr[0]===2
, so we are adding 0+2, and returning the result. Returning it where? To the next outward function call.
There, n===2
, and we take that returned 2
from our nested box, and add it to arr[1]
, which is 3 - so this box is returning 2+3
… to the thing that called it. Our outermost box.
That outermost box (which still sees n===3
) catches the 5
and adds arr[2]
to it. arr[2]===4
, so we’re going to return 4+5
. And where does that get returned? Back to whatever called the function originally. Each time, the function is returning some value to the place that called it. In this case, we’re at the outermost box, so we’re returning that 9
to our console.log()
or our test or whatever called the function originally.
Let’s try a visual:
sum([2,3,4,5], 3)
= sum([2,3,4,5], 2) + 4
= { sum([2,3,4,5], 1) + 3 } + 4
= { { sum([2,3,4,5], 0) + 2} + 3 } + 4
// here, we've reached the innermost level.
// we're going to return 0 and start unwrapping our nesting!
= { { { 0 } + 2 } + 3 } + 4
= { { 0 + 2 } + 3 } + 4
= { 2+3 } + 4
= 9
Our final return value = 9
That nested math thing might look scary, but what’s happening is that each pair of { }
shows a “scope”. It’s the nested function call again! Each one of those will evaluate, from the innermost first. Each call is indented to indicate the “nesting”, until we reach that innermost level, and then we return its evaluation (0
), and then we work our way back out (by following the return statements. From the comment above down, we’re simply passing back the result to the innermost {...}
each time, evaluating that, and passing it along.
Recursion is confusing, and until you really start using it a lot, it will continue to be confusing. the more you use it, the less confusing it should get… but it never seems normal to me. Feels like trying to look inside my own head with my own eyeballs.