Implementing lazy evaluation in JavaScript with memoized functions

Lazy evaluation is a programming technique where the evaluation of an expression is delayed until its value is actually needed. This can help improve performance and efficiency, especially when dealing with large computations or infinite sequences.

In JavaScript, we can implement lazy evaluation using memoized functions. Memoization is a technique where the output of a function is cached based on its input. This allows us to avoid redundant computations and retrieve the already computed result whenever the function is called with the same arguments.

Let’s see how we can implement lazy evaluation with memoized functions in JavaScript:

function memoize(fn) {
  const cache = {};
  
  return function(...args) {
    const key = JSON.stringify(args);
    
    if (cache[key]) {
      return cache[key];
    }
    
    const result = fn.apply(this, args);
    cache[key] = result;
    
    return result;
  };
}

In the code above, we define a memoize function that takes a function fn as its argument. This function returns a new function that wraps the original function with memoization logic.

Inside the memoized function, we create a cache object to store the computed results. We use JSON.stringify to create a unique key based on the arguments passed to the function. If the result for a given set of arguments is already present in the cache, we simply return it.

If the result is not present in the cache, we call the original function fn with the provided arguments using the apply method. We then store the computed result in the cache object before returning it.

To use the memoized function, we simply pass our original function as an argument to the memoize function:

function expensiveComputation(n) {
  console.log("Computing...");
  return n * 2;
}

const memoizedComputation = memoize(expensiveComputation);

console.log(memoizedComputation(5)); // Output: Computing... 10
console.log(memoizedComputation(5)); // Output: 10 (cached result)
console.log(memoizedComputation(10)); // Output: Computing... 20
console.log(memoizedComputation(10)); // Output: 20 (cached result)

In the example above, we define an expensiveComputation function that simply multiplies a number by 2. We then create a memoized version of this function by passing it as an argument to the memoize function. We can see that the first time we call the memoized function, it performs the computation and logs “Computing…”, but subsequent calls with the same arguments retrieve the cached result without recomputation.

By using lazy evaluation with memoized functions, we can optimize our code and improve performance by avoiding unnecessary computations. This technique can be particularly useful when dealing with complex algorithms, recursive functions, or processing large amounts of data.

#programming #javascript