Memoize

Prompt
Your task is to write a JavaScript function named memoize
.
This function should take in another function as an argument and return a memoized version of it.
Solution
Explanation 🧠
-
The
memoize
function is a higher-order function that takes another function fn as an argument. -
Inside the
memoize
function, an emptyMap
instancecache
is created, which will be used to store the memoized results. -
The
memoize
function returns a new function using an arrow function syntax. -
Inside the returned function, the arguments passed to the function are stringified using
JSON.stringify
to create a key for thecache
Map. -
If the key exists in the
cache
Map (checked usingcache.has(key)
), it means the function has been called with those arguments before, so it simply returns the cached result from the Map usingcache.get(key)
. -
If the key doesn't exist in the
cache
Map, it means the function hasn't been called with those arguments before, so it calls the original functionfn
with the given arguments using the spread syntaxfn(...args)
, stores the result in thecache
Map usingcache.set(key, result)
, and returns the result. -
The first time
memoizedSquare(140)
is called, the memoized function doesn't find the result in thecache
object, so it calls the originalsquare
function with 140 as the argument, calculates the result, stores it in thecache
object, and returns the result. -
The second and third times
memoized
Square(140)
is called, the memoized function finds the result in thecache
object using the key"140"
, and it simply returns the cached result without calling the originalsquare
function again.
The Map provides better performance for key-value storage and retrieval compared to objects, especially when dealing with non-string keys.
⬆️ Level up #1 (Measure Performance)
How can you measure the time taken by each operation to evaluate the effectiveness of memoization?
Solution
Explanation 🧠
To evaluate the benefits of memoization, one can use the console.time()
and console.timeEnd()
functions to compare the duration of operations conducted with and without the application of memoization.
For instance, in the example provided above, we are calculating the square of a number. The initial computation requires a significant amount of time because the result isn't initially cached. However, if one inspects the console logs, they'll notice that subsequent computations are considerably quicker. This speed is due to the results now being stored in the cache, enabling the function to retrieve them directly from the cache rather than recomputing them.
Note 📄
Imagine you're cooking Palak Paneer, a delicious Indian vegetarian dish, and you want to time how long it takes. Here's how you'd do it:
- Start the stopwatch when you begin cooking. In our code, we'll call
console.time('Cooking Palak Paneer')
- Cook your dish. In the JavaScript world, this represents any task you want to time. It could be a complex calculation, loading data, or anything that requires time to complete.
- Stop the stopwatch when you finish. In the code, you'll call
console.timeEnd('Cooking Palak Paneer')
console.time('Cooking Palak Paneer'); // Start the stopwatch (or timer)
// This is where you "cook" in your code, i.e., perform the operation you're timing.
for (let i = 0; i < 100000; i++) {
// Here, we're just looping many times as a placeholder for the cooking process.
}
console.timeEnd('Cooking Palak Paneer'); // Stop the stopwatch (or timer)
When you run this code, the console (think of it as your digital kitchen timer) will tell you how long it took to "cook the Palak Paneer". You'll see a message something like this: "Cooking Palak Paneer: 35ms"
. This means it took 35 milliseconds to run the code between the start and end commands. Keep in mind this is a simple example, and the real process of cooking Palak Paneer is a lot more enjoyable! 🍽️ 💖