DEV Community

Cover image for Memoization and the Magic of Self-Containing Functions
Corina: Web for Everyone
Corina: Web for Everyone

Posted on

Memoization and the Magic of Self-Containing Functions

How JavaScript Functions Remember Their Past

In JavaScript development, caching data for quick retrieval is paramount. We instinctively reach for objects as key-value stores or arrays for ordered lists. Some of us might even delve into specialized data structures like Maps and Sets to optimize performance.

However, there's a lesser-known, yet universally available, method that many of us overlook: functions themselves. Every function in JavaScript has the capability to hold onto data, effectively using itself as a memory bank. 😲

Let's explore how!


Case: Finding the Factorial of a Number βš™οΈ

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

So 6! = 1 x 2 x 3 x 4 x 5 x 6 = 720

An Example with Recursion πŸ”„

Let's look at the function below that uses recursion to calculate the factorial of an input.

Just a reminder: recursion is a programming concept where a function calls itself. Please note that this example does not use tail recursion, which is the more efficient way to use recursion in JavaScript.

function factorial(n) {
    // Input validation
    if (!Number.isInteger(n) || n < 0) {
      return NaN;
    }

    // Base cases
    if (n === 0 || n === 1) {
      return 1;
    }

    // Check if the result has already been cached
    if (n in factorial) {
      return factorial[n];
    }

    // Recursive call and caching
    factorial[n] = n * factorial(n - 1);
    return factorial[n];
}

Enter fullscreen mode Exit fullscreen mode

Now let's see what happens ...

When Functions Remember πŸ“

Let’s have a closer look at this section from the code above:

if (n in factorial) {
    return factorial[n];
}
Enter fullscreen mode Exit fullscreen mode

This is an example of memoization - storing the results of function calls and returning the cached result when the same inputs occur again. Normally, to use memoization, you create an array or object to store already computed values. But this function uses itself to store previously computed results!

How cool is that! 😎

Why? Because it can! In JavaScript, functions are objects, therefore you can add properties to them. In this case, previous results of the factorial calculation are stored as properties on the function itself with the input value n as the key.

So when we run factorial(6) the output is 720, and if we print factorial JavaScript shows the function and its properties. The properties are displayed as key-value pairs following the function definition, showing that the function has stored the computed values for future use:

[Function: factorial] 
{ '2': 2, '3': 6, '4': 24, '5': 120, '6': 720 }
Enter fullscreen mode Exit fullscreen mode

Notice the properties that have been added to the function object:

  • the numbers '2', '3', '4', '5', '6' are the keys, and
  • their respective values are 2, 6, 24, 120, and 720, representing the factorials of those numbers represented by the keys.

The factorial function is indeed acting as its own cache or container! If you ever doubted the power and flexibility JavaScript has to offer, let this be a moment of enlightenment. πŸ“¦ πŸ’‘

(Ok, Python can do this as well. But this is not a competition, right? πŸ˜‰)

Resources

Noticed how I like to recommend this book?! 😎

  1. JavaScript: The Definitive Guide
    7th Edition, by David Flanagan
    O'Reilly Media, 2020

  2. MDN Documentation on JavaScript Functions

Blog post originally published August 29, 2023 on corinamurg.dev.

Credit: Photo by Ines A. on Unsplash

Top comments (0)