Q29: Implement a memoize() utility for caching function results.

Difficulty:IntermediateTopic:Caching

Answer

Memoization caches the result of a function call so repeated calls with the same inputs can reuse the previous result.

function memoize(fn) {
  const cache = new Map();

  return function (...args) {
    const key = JSON.stringify(args);

    if (cache.has(key)) {
      return cache.get(key);
    }

    const result = fn.apply(this, args);
    cache.set(key, result);

    return result;
  };
}

const slowSquare = memoize(n => {
  console.log("Calculating...");
  return n * n;
});

console.log(slowSquare(5)); // Calculates... 25
console.log(slowSquare(5)); // 25, retrieved from cache

Explanation

The wrapper computes a cache key from the arguments. If the key exists, it returns the stored result; otherwise, it calls the original function and caches the result.

Interview edge cases

  • JSON.stringify() can produce collisions for certain inputs and cannot serialize all JavaScript values.
  • Object identity is not preserved by JSON serialization.
  • The receiver, this, may affect the function's result but is not included in the key.
  • Unbounded caches can grow indefinitely.

A production implementation should choose a cache-key strategy appropriate to the function's inputs. For a function that accepts only primitive arguments, a nested Map structure can provide safer key semantics.

Key Takeaways
  • Memoization reuses results for repeated inputs.
  • Cache keys and cache invalidation must be designed carefully.