Home » JavaScript Recursive Functions: A Complete Tutorial with Examples

JavaScript Recursive Functions: A Complete Tutorial with Examples

In JavaScript, recursive functions are functions that call themselves.

They are especially useful for solving problems that can be broken down into smaller, similar subproblems.

A recursive function continues to call itself until it reaches a base case—a condition that stops the recursion.

Key Components of Recursive Functions

Base Case: The condition that stops the recursion. Without a base case, the function would call itself indefinitely, leading to a stack overflow error.
Recursive Case: The part of the function where the recursion happens. It involves the function calling itself with modified parameters.

Example 1: Basic Recursive Function – Factorial

A factorial of a non-negative integer n is the product of all positive integers less than or equal to n. The factorial of n is denoted as n!.

Factorial Formula

Base Case: 0! = 1
Recursive Case: n! = n * (n – 1)!
Example Code

function factorial(n) {
  // Base case: if n is 0, return 1
  if (n === 0) {
    return 1;
  }

  // Recursive case: n * factorial(n - 1)
  return n * factorial(n - 1);
}

console.log(factorial(5)); // Output: 120

Explanation

The function factorial calls itself with a decremented value of n.
When n reaches 0, it hits the base case and returns 1, which stops the recursion.
The recursive calls then multiply to produce the final result (5 * 4 * 3 * 2 * 1 = 120).

Example 2: Fibonacci Sequence

The Fibonacci sequence is a series of numbers where each number is the sum of the two preceding ones, starting from 0 and 1.

Fibonacci Formula

Base Cases: fib(0) = 0, fib(1) = 1
Recursive Case: fib(n) = fib(n – 1) + fib(n – 2)

Example Code

function fibonacci(n) {
  // Base cases: if n is 0 or 1, return n
  if (n === 0) {
    return 0;
  } else if (n === 1) {
    return 1;
  }

  // Recursive case: fib(n) = fib(n - 1) + fib(n - 2)
  return fibonacci(n - 1) + fibonacci(n - 2);
}

console.log(fibonacci(6)); // Output: 8

Explanation

The function fibonacci calls itself twice with decremented values (n – 1 and n – 2).
The recursion continues until it hits the base cases (n = 0 or n = 1).
The results of the recursive calls are added together to produce the Fibonacci number at position n.

Example 3: Sum of an Array

You can use recursion to find the sum of elements in an array.

Example Code

function sumArray(arr) {
  // Base case: if the array is empty, return 0
  if (arr.length === 0) {
    return 0;
  }

  // Recursive case: sum of first element + sum of the remaining array
  return arr[0] + sumArray(arr.slice(1));
}

let numbers = [1, 2, 3, 4, 5];
console.log(sumArray(numbers)); // Output: 15

Explanation

The function sumArray takes an array and adds the first element (arr[0]) to the sum of the remaining elements (arr.slice(1)).
The recursion stops when the array is empty (arr.length === 0), which is the base case.

Example 4: Flatten a Nested Array

A recursive function can also be used to flatten a nested array.

Example Code

function flattenArray(arr) {
  let result = [];

  arr.forEach(element => {
    if (Array.isArray(element)) {
      // Recursive case: if the element is an array, concatenate the flattened result
      result = result.concat(flattenArray(element));
    } else {
      // Base case: if the element is not an array, add it to the result
      result.push(element);
    }
  });

  return result;
}

let nestedArray = [1, [2, [3, 4], 5], 6];
console.log(flattenArray(nestedArray)); // Output: [1, 2, 3, 4, 5, 6]

Explanation

The function flattenArray uses recursion to handle nested arrays.
It iterates over each element in the array. If an element is an array, it recursively flattens it and concatenates the result.
If an element is not an array, it adds the element directly to the result.

Example 5: Counting Down Recursively

A simple example of a recursive function is counting down from a given number to 0.

Example Code

function countdown(n) {
  // Base case: if n is less than or equal to 0, return
  if (n <= 0) {
    console.log('Countdown finished!');
    return;
  }

  // Print the current number
  console.log(n);

  // Recursive case: call countdown with n - 1
  countdown(n - 1);
}

countdown(5); 
// Output:
// 5
// 4
// 3
// 2
// 1
// Countdown finished!

Explanation

The function countdown prints the current number and then calls itself with n – 1.
The recursion stops when n is less than or equal to 0 (base case).

Example 6: Directory Traversal (Nested Objects)

Recursion can be used to traverse through nested objects, such as a directory structure.

Example Code

let directory = {
  name: 'root',
  files: ['file1.txt', 'file2.txt'],
  subDirectories: [
    {
      name: 'subDir1',
      files: ['file3.txt'],
      subDirectories: []
    },
    {
      name: 'subDir2',
      files: [],
      subDirectories: [
        {
          name: 'subSubDir1',
          files: ['file4.txt'],
          subDirectories: []
        }
      ]
    }
  ]
};

function listFiles(directory) {
  let files = [...directory.files];

  directory.subDirectories.forEach(subDirectory => {
    files = files.concat(listFiles(subDirectory));
  });

  return files;
}

console.log(listFiles(directory)); 
// Output: ['file1.txt', 'file2.txt', 'file3.txt', 'file4.txt']

Explanation

The function listFiles takes a directory object and returns an array of all files within it, including those in nested subdirectories.

It uses recursion to traverse each subdirectory.

Summary

Key Points

Recursive functions are functions that call themselves to solve a problem.
Base case: The condition that stops the recursion. It’s crucial to include a base case to avoid infinite recursion.
Recursive case: The part of the function that calls itself with modified parameters.

Recursive functions are ideal for problems that can be broken down into similar subproblems, such as factorials, Fibonacci numbers, nested data structures, and more.

Pros and Cons of Recursion

Pros: Simplifies code for complex problems like tree traversal, mathematical computations (e.g., factorials, Fibonacci), and working with nested data structures.
Cons: Can be less efficient than iterative solutions due to function call overhead. If not carefully managed, recursion can lead to a stack overflow.

When to Use Recursion

When a problem can be naturally divided into smaller, similar subproblems.
When dealing with nested structures, such as nested arrays or objects.
When the problem is better expressed in terms of itself.

Recursion is a powerful concept in programming, and understanding how to use it effectively can greatly expand your problem-solving abilities in JavaScript.

You may also like