0

I'm a beginner going through a JS tutorial and got stuck trying to understand the order of statement execution in this example of a recursive function:

function countup(n) {
  if (n < 1) {
    return [];
  } else {
    const countArray = countup(n - 1);
    countArray.push(n);
    return countArray;
  }
}
console.log(countup(5)); // Output is [ 1, 2, 3, 4, 5 ]

I assumed, that each time const countArray = countup(n - 1); line is reached, it throws the execution back to line 1 with decremented n. That would explain the output array starting at 1 and going upwards, while n is going down. But in that case, shouldn't the function just return empty array [], since n would drop below 1, satisfying the first if and terminating before anything having been pushed into countArray (else)? **Tried googling about the use of breakpoints to see the actual flow, but only saw their uses in non-loops

5
  • 1
    A breakpoint is a breakpoint, regardless of if it's in a loop or not. console.log can also be your friend. But I'm not sure I understand your explanation of what's happening: When countup(n - 1) is hit the function is called again with the new value for n on entry. n won't be less than one until... it's less than one, e.g., first time, it'll be 4. Commented Aug 25, 2020 at 17:04
  • 5
    IMO you'd be best served by "playing computer" with pencil and paper--just pretend you're the computer, write down each step, and remember that execution will resume immediately after the recursive call to countup, for each execution of countup. Commented Aug 25, 2020 at 17:05
  • 1
    Pay particular attention to what conditional branch is taken during each call. E.g., for the first iteration, what branch is taken? What's returned? For the first iteration, does it return immediately, or does it make the recursive call? Hint: your pen/cil & paper exercise, if you indent each call, should look like a backslash for most of it. Commented Aug 25, 2020 at 17:07
  • const countArray = countup(n - 1); doesn't throw the execution back to line 1! It makes another call to countup with n-1, once that call returns, the current invocation continues and returns it's own value. Commented Aug 25, 2020 at 17:14
  • 1
    Very related: recursion: storage of multiple values in variables; The empty array in this recursive code is accessible how?, Understanding recursive loop that returns an inverted count. There have been many questions about this same function in relation to recursion. Commented Aug 25, 2020 at 17:16

2 Answers 2

3

Let's simply assume that every function call with all its information will be stored in a stack. Note, stacks are LIFO(Last In First Out).

So in your code, countup(5) will be called and stored in stack[0].

Then inside the else condition it is again called as countup(4). This will pause countup(5) from being executed and countup(4) will be stored in the stack[1].

Just like this until n<1 countup will be called with a lower value and stored in stack.

At the end of all calls, stack will be like,

 - stack[4]    countup(1)
 - stack[3]    countup(2)
 - stack[2]    countup(3)
 - stack[1]    countup(4)
 - stack[0]    countup(5)

Now popping from stack will start. As stack is LIFO so element at top of the stack will be popped. Popped means you're deleting that element from your stack.

countup(1) will be popped first and finish its execution. That is countArray.push(1).

Then countup(2) will be at the top of stack. So, countup(2) is popped and finish its execution countArray.push(2).

Just like this, countup(3) is popped and finish its execution countArray.push(3). countup(4) is popped and finish its execution countArray.push(4). countup(5) is popped and finish its execution countArray.push(5).

At the end the entire array is returned.

*I've described it in simple terms. The real execution behind the hood has a lot more things going and has a lot other terms to know about. You can check this article that describes how recursion works in JS

Sign up to request clarification or add additional context in comments.

Comments

0

I don't know if you're familiar with the "spread" syntax, but it might be easier to see what's going on if the body of the else clause were written as simply:

return [...countUp(n - 1), n];

That just means it's the array you get by taking countUp(n - 1) and adding the element n at the end. The code you show does the same, just in a slightly different way. Hopefully it's obvious from this description why the function does what it does - but if it still isn't, note that:

  • countUp(0) is empty
  • countUp(1) therefore consists of an empty array with an additional 1 on the end - so the singleton array [1]
  • countUp(2) is the above with a 2 on the end: [1, 2]

and so on.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.