Recursion in JavaScript

Recursion in JavaScript

·

3 min read

One thing I really struggled with was understanding functions that call themselves.

At first, recursion seemed confusing because I wasn’t sure how and why a function would keep calling itself.

Recursion is a programming concept where a function calls itself to solve a problem. It’s especially useful for working with nested structures or breaking down complex problems into smaller, manageable parts—especially when the depth is unknown.

Before we look at recursive functions let’s start with a simple example where one function calls another:

function log() {
  console.log("Hello World");
  logName("Hamza");
}

function logName(name) {
  console.log(name);
}

log();

Here, we are simply defining two different functions: log() and logName(name).

The log() function first logs "Hello World" to the console and then calls the logName(name) function, which logs whatever name we pass to it.

Now, what if the log() function called itself instead of calling logName(name)? It would look like this:

function log() {
  console.log("Hamza");
  log();
}

log();

First, we define the function body of log(), which logs a name to the console and then calls itself.

This is what recursion means—when a function invokes itself.

The problem with this recursive function is that it calls itself infinitely, which leads to a stack overflow error once the maximum call stack size is exceeded.

Now, let’s look at an example where recursion happens without running infinitely:

function logI(i) {
  if (i > 3) return;

  console.log(i);
  logI(i + 1);
  console.log(i);
  return;
}

logI(1);

If we run this code, our console output will look like this:

1
2
3
3
2
1

Let’s go through the code line by line.

We start our first function call: logI(1), where i = 1.

  • The if statement is ignored because i is not greater than 3.

  • i gets logged to the console → we see 1 as the first log.

  • Now, logI(i + 1) is called, meaning logI(2) starts executing.

  • Our current function call logI(1) gets added to the call stack since it hasn't finished yet.

Now inside logI(2):

  • The if statement is ignored again (i = 2 is not greater than 3).

  • 2 gets logged to the console → second log.

  • Another recursive call is made: logI(3).

  • logI(2) gets added to the call stack, waiting to return.

Now inside logI(3):

  • The if statement is ignored (i = 3 is not greater than 3).

  • 3 gets logged to the console → third log.

  • Another recursive call is made: logI(4).

  • logI(3) gets added to the call stack, waiting to return.

Now inside logI(4):

  • The if statement is true (i > 3), so the function returns immediately.

  • No console log happens here!

At this point, we have three paused function calls on the call stack:

logI(3)
logI(2)
logI(1)

Now, the function calls start resolving one by one, beginning with the most recently added function call: logI(3).

In our example, we log i after the recursive call logI(i + 1), which is why the number 3 appears again in our fourth log. After that, the function simply returns.

The same thing happens in the logI(2) and logI(1) calls:

  • i gets logged again, which prints 2, then the function returns.

  • Finally, i = 1 gets logged again, and the last function call returns.

At this point, the call stack is completely empty, meaning all recursive calls have finished executing.

What helped me the most was realizing that every recursive function stays in the call stack until it returns. Once I saw recursion as a series of 'paused' function calls waiting to finish, it became much easier to understand.

Thanks for reading! Hope this helped and happy coding! 🚀