Recursion

JavaScript ES2024 · ✓ verified by execution on 2026-08-15

Recursion is a programming technique where a function calls itself to solve a smaller instance of the same problem. While loops like for and while rely on mutable state to track progress, recursion relies on the function call stack. This functional approach is especially powerful when traversing hierarchical data structures, like the DOM tree or complex nested JSON objects, where the depth of the nesting is unknown ahead of time.

A recursive function must have a condition to stop calling itself. Otherwise, the function will call itself indefinitely.

Without a stopping condition, recursion is no different from an infinite loop. However, instead of just freezing the browser, an infinite recursion will violently crash the engine as it runs out of memory allocated for the call stack. Let’s look at a simple countdown, mapping out how the stack frames grow:

countdown(2) countdown(1) countdown(0) Base Case Reached Stack Unwinds
A recursive call stack: each countdown() call stacks on the one before it until the base case is reached, then the stack unwinds back through every pending frame.

Notice how we have a condition to halt the recursion:

javascript · visualize
function countdown(n) {
  console.log(n);
  if (n <= 0) return;
  countdown(n - 1);
}
countdown(2);
2
1
0

The Danger of Infinite Recursion

If the base case is omitted… the execution stack will overflow. What happens if we run a recursive function without a base case? Let’s predict!

function infinite() {
  return infinite();
}
// infinite(); // Causes stack overflow

The // infinite() call was commented out to save your browser. If you uncommented it, the runtime would abort execution, throwing a Maximum call stack size exceeded error.

The Call Stack and Unwinding

When the current function finishes, the interpreter takes it off the stack and resumes execution where it left off in the last code listing.

Each time a function calls itself, execution of the current function pauses, and a new execution context is pushed to the call stack. Once the base case is hit, the stack “unwinds”. This means the code after the recursive call gets executed in reverse order (Last In, First Out).

Run this code and predict the output to see unwinding in action:

Predict the output javascript

Read the code. What exactly will it print? Commit to an answer before you look.

function climb(steps) {
  if (steps === 0) {
    console.log('Top!');
    return;
  }
  console.log('Up ' + steps);
  climb(steps - 1);
  console.log('Down ' + steps);
}
climb(2);
Output
Up 2
Up 1
Top!
Down 1
Down 2

Using Recursion to Accumulate Results

Often, recursion is used to aggregate data (like multiplying a sequence of numbers). A function can call itself… returning the result of the recursive call is critical. If you forget to return the result of the recursive call, the accumulated value will be lost, and the outer function will return undefined.

javascript
function factorial(n) {
  if (n === 0) return 1;
  return n * factorial(n - 1);
}
console.log(factorial(3));
Output
6

Mastering recursion is a core skill that makes traversing trees, nested objects, and graphs significantly easier!

Check yourself

What happens when a recursive function reaches its base case?

Reveal answer

The base case stops new calls, and the call stack begins to unwind. — The base case only stops new calls from being made. The stack must still unwind, meaning all previous calls will finish executing.

How are variables handled in recursive calls?

Reveal answer

Every call creates a brand new execution context, preserving its own separate variables. — Every call creates a brand new execution context. The variables are completely separate and preserved.

Why is the return keyword important in recursion?

Reveal answer

If you don't return the recursive call, the final computed value won't bubble back up. — If you don't return the recursive call, the final computed value won't bubble back up, resulting in `undefined`.

How does recursion differ from a standard loop?

Reveal answer

Recursion builds a call stack and can branch, whereas a loop runs in a single frame. — While they both repeat code, recursion builds a call stack and can branch (like in a tree traversal), whereas a loop runs in a single frame.

Challenges

Challenge 1 +20 XP

Write a recursive function `sumRange(n)` that returns the sum of all numbers from 1 to `n`. For example, `sumRange(3)` should return `6`.

javascript
  • Test 1 — expects "6"
Need a hint? (−25% XP)

What is the base case where you can stop? If n is 1, return 1.

Show solution (0 XP)
function sumRange(n) {
  if (n === 1) return 1;
  return n + sumRange(n - 1);
}
console.log(sumRange(3));

🐞 Bug Hunt +50 XP

This recursive function is supposed to count down to 1, but it causes a stack overflow instead. Fix the bug.

This code runs. It just does the wrong thing. Read it, find the defect, fix it — the tests below decide when you are right.

javascript
  • Test 1 — expects "3\n2\n1"
Need a hint? (−25% XP)

The recursive call passes `n` instead of `n - 1`, so the number never changes.

Show solution (0 XP)
function countdown(n) {
  console.log(n);
  if (n === 1) return;
  countdown(n - 1);
}
countdown(3);