Use recursion to create a range of numbers example

So I’ve just been going through some of these recursive exercises and like a lot of people they have been confusing for me. I just got to this one and the example didn’t quite make sense to me.

function count(n) {
  if (n === 1) {
    return [1];
  } else {
    var numbers = count(n - 1); 
    numbers.push(n);
    return numbers;
  }
}

I ran it in console with debugger and stepped through it using count(5); and here is what seems to happen:

The function begins and n is not equal to 1 so it skips to
var numbers = count(n-1);
so far so good. It does this for 5,4,3,2, and finally hits 1. Then it runs and 1 === 1 so it returns 1.

Then it jumps to numbers.push(n); and starts iterating back up to 5. HOW DOES THIS HAPPEN??? How does it jump from the return statement in the if section into the push statement of the else block??? That makes absolutely no sense to me so please help me understand it. Thanks for you time.

have you checked the explanations on those other threads? did you not understand the explanations there?
these are two explanations I wrote in the last two days. does this help?

1 Like

Yes, I read your responses and unfortunately the way you word things does not make sense to me. I think in reading skaparate’s response I understand now that once n = 1, var numbers = [1]. What I am struggling with now is the way in which return is working, because I would expect it to exit the function after returning the array once the second value has been pushed. I.e. return [1,2]. Why does it continue to loop after the return statement executes the first time?

1 Like

well the function returns a value and stop running, but that function was called by an other function
it is like chinese boxes, one function inside the other, the inner most one rethrns a value, and gives its output to the function that had called it, and so on till each function called have given an output

maybe try looking at it with this:

http://pythontutor.com/javascript.html#mode=edit

1 Like

So the function actually calls n nested subfunctions inside of the function, and each resolution returns a value that is then pushed into the array and returned again until the last subfunction has been returned? So the output would actually look like
[1]
[1,2]
[1,2,3]
[1,2,3,4]
[1,2,3,4,5]

is this correct?

That sounds correct. Let me see if I can help break this down a little better. On the way “down”, each iteration (recursive call) halts on the line var numbers = count(n - 1); and waits to assign the return value of count(n - 1) to the variable numbers. It seems we don’t have a problem understanding that it is recursively called with 5, 4, 3, 2, and 1.

Then, as you stated, it satisfies the base condition (n === 1). It executes the code return [1], and begins working its way back “up” all of the waiting function calls. The first return value is [1] which is assigned to the variable numbers. The next line of code is executed which is numbers.push(n);. In this function call, n is set to 2. Now numbers looks like [1, 2]. The next statement is executed which is return numbers; and so it returns [1, 2] to the next waiting function call which assigns it to its variable named numbers. In that function, n is set to 3, so the line numbers.push(n) results in numbers equaling [1, 2, 3] which is returned to its waiting function call.

This continues until all of the waiting function calls are executed and finished. The final one, which was the first one called, has n set to 5. It pushes 5 onto the array and returns [1, 2, 3, 4, 5] and the process is complete.

4 Likes

Thank you this helps clarify it for me.

1 Like

Yeah, sorry ieahleen, your explanations do not make any sense to me either.

A better question is why are we even using recursion in this day and age in the first place, it’s incredibly buggy and super difficult to setup so that it doesn’t crash anything along the way. There are much simpler ways of solving these problems.

what do you not understand? What are you not understanding about recursion?

Hey @free4mOriginal, I’m afraid you’re mistaken on multiple counts:

I might be wrong but I feel you mean something like good old flow control, i.e. while loop
If I’m correct, then I have bad news for you, as imperative programming is by far more buggy and non-scalable comparing to declarative (incl. recursion).

There is no such thing as recursion in JavaScript. When you write something like this:

const a = f(b);

Then engine will always invoke f(b) first and only then will proceed to assignment. Function f() will most likely require other functions to run prior to calculate the outcome - it’s natural modular approach and recursion is nothing else as THIS.

You should not mythify recursion!

I was NOT suggesting the use of while loops, or “good old flow control” (not sure where that came from). And recursion IS known to be quite buggy.

So if I understand well this is actually a Closure Scope Chain, right? As on the mdn (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures) websites explain it.
Could someone confirm this to me?
Thank you

No, there’s no closure used in this example

Hi, awesome to read so many people try to explain this matter.

Imo, the exercise itself is not the issue, much more so to understand the concept behind it.

I’m struggling as well to understand exactly the mechanics of this.
I think a clarification on what the Call Stack is and a visual approach to it in this particular case would help all who share this problem.
The chinese boxes analogy makes lots of sense to me, just feeling it is a little confusing to factor in the return operator.

Cheers to everyone feeling to tackle this and make this lesson more applicable!

much thanks to @ilenia for this!

1 Like

This video has a nice explanation of recursion and the call stack:
https://www.youtube.com/watch?v=aCPkszeKRa4

1 Like

Did you see the movie inception? I made a painting for you, enjoy!

2 Likes

This ‘painting’ actually helped me better understand recursion. Thanks!

2 Likes

I am glad! No problem!

How is it that the “else” return execution doesn’t end the function like any other return?