Back to blog

Date

A Focus on Recursion in JavaScript

Welcome, JavaScript folks! Today, we delve into the interesting world of recursion, a programming concept that can both beguile and empower coders. We'll take a look at what recursion is, talk about the building blocks of recursion, common pitfalls and explore when recursion shines (and when it might not).

1. What is Recursion?

Recursion, in essence, is a function's ability to call itself. It creates a self-referential loop where the function breaks down a problem into smaller, similar subproblems, eventually reaching a base case that halts the recursion and provides the final answer. Imagine a set of Russian nesting dolls: the largest doll contains a smaller doll, which in turn contains an even smaller one, and so on, until you reach the tiniest doll. Recursion works similarly, with each function call representing a smaller version of the original problem.

2. Building Blocks of a Recursive Algorithm

Here are the building blocks to build a recursive algorithm:

Let's dive into some code examples to solidify these concepts.

3a. Example #1: Summing a List of Numbers with Recursion

We'll start with the example of summing a list of numbers using recursion.


          function sumRecursive(list) {
            if (list.length === 0) {
              return 0; // Base case: empty list sum is 0
            } else {
              const firstElement = list[0];
              const remainingList = list.slice(1);
              return firstElement + sumRecursive(remainingList); // Recursive case
            }
          }
          
          const numbers = [1, 2, 3, 4, 5];
          const sum = sumRecursive(numbers);
          console.log(sum); // Output: 15
        

3b. Summing a List of Numbers with Iteration (For Comparison)

Here's how we might achieve the same result using a for loop (iteration):


          function sumIterative(list) {
            let sum = 0;
            for (const num of list) {
              sum += num;
            }
            return sum;
          }
          
          const numbers = [1, 2, 3, 4, 5];
          const sum = sumIterative(numbers);
          console.log(sum); // Output: 15
        

This iterative approach is generally considered more efficient for simple tasks like summation. However, recursion shines in solving problems with a naturally recursive structure, as we'll see in the next example.

4a. Example #2: Fibonacci Sequence with Recursion

The Fibonacci sequence is a famous mathematical series where each number is the sum of the two preceding numbers (except the first two numbers, which are typically defined as 0 and 1). Let's see how recursion tackles this problem:


          function fibonacciRecursive(n) {
            if (n <= 1) {
              return n; // Base case: 0 or 1
            } else {
              return fibonacciRecursive(n - 1) + fibonacciRecursive(n - 2); // Recursive case
            }
          }
          
          const number = 6;
          const result = fibonacciRecursive(number);
          console.log(result); // Output: 8
        

4b. Example #2: Fibonacci Sequence with Iteration (For Comparison)


          function fibonacciIterative(n) {
            // Handle negative or zero input
            if (n <= 0) {
              return 0;
            }
          
            // Initialize first two Fibonacci numbers
            let a = 0;
            let b = 1;
          
            // Iterate n-1 times (since the first two numbers are already defined)
            for (let i = 2; i <= n; i++) {
              let c = a + b;
              a = b;
              b = c;
            }
          
            // Return the nth Fibonacci number
            return b;
          }
          
          // Example usage
          console.log(fibonacciIterative(5)); // Output: 5
          console.log(fibonacciIterative(10)); // Output: 55          
        

Alright, we've reached the halfway point in our exploration of recursion in JavaScript. If your mind is a little blown right now, that's perfectly normal! Recursion can be a head-scratcher at first, but with practice, it becomes a powerful tool.

In the previous section, we saw how recursion can be used to solve problems like summing a list of numbers and generating the Fibonacci sequence. However, it's crucial to understand the potential pitfalls and trade-offs when using recursion compared to iterative approaches.

5. Common Pitfalls of Recursive Programs

Here's an example of a potential stack overflow with recursion:


          function wrongFactorial(n) {
            if (n === 0) {
              return 1;
            } else {
              return n * wrongFactorial(n); // We never change the value of n
            }
          }
          
          wrongFactorial(5); // This will result in a stack overflow error
        

This function attempts to calculate the factorial of a number (3! = 3 * 2 * 1). However, it lacks a clause to change the value of n. This would cause the function to call itself infinitely, leading to a stack overflow error.

6. Recursion vs Iteration

So, when should you choose recursion over iteration? Here are some ideas on that:

Ultimately, the choice between recursion and iteration depends on the specific problem you're trying to solve. Consider the trade-offs in terms of readability, performance, and potential for stack overflows.

Hopefully this was a helpful introduction or refresher on recursion! Definitely practice problems on platforms like Leetcode to solidify your understanding! Cheers!