Closures: Using Memoization

7/5/2019 · 2 minute read · 2 comments · 4122 views

Orginally posted on dev.to.

One of the core tenets of Functional Programming is that a function should return the same value if given the same input, every single time. Memoization is the practice of taking a function that is recursive or iterative and making it run faster. This is usually by caching the values it processes.

const multiplyCache = {}

const multiplyBy2 = num => {
  if (multiplyCache[num]) {
    return multiplyCache[num]
  }
  const total = num * 2
  console.log('Loading...') // To represent this process taking time
  multiplyCache[num] = total
  return total
}

console.log(multiplyBy2(5))
console.log(multiplyBy2(2))
console.log(multiplyBy2(5))
console.log(multiplyBy2(2))

// The first time we run the function with 5 and 2, we get Loading... 
// before we get the total. The second time with each, we fetch 
// it from the cache instead.

This very basic example is how caching works. We store our results in the object so we can refer to them later, letting it take far less time to do so.

So where do closures play into this? Well, they give us even more power with memoization, allowing us to hold onto our cached values as well as keep them protected.

const specialNum = () => {
  let cache = {}
  return name => {
    if (cache[name]) {
      return cache[name]
    }
    console.log('Generating special number...') // To represent this process taking time
    const rand = Math.floor(Math.random() * 3 + 1)
    cache[name] = rand
    return rand
  }
}

const generateSecretNum = specialNum()

const specialNumBrian = generateSecretNum('brian')
const specialNumPiper = generateSecretNum('piper')

console.log(specialNumBrian) // Will generate, since it's the first time.
console.log(specialNumPiper) // Will generate, since it's the first time.
console.log(specialNumBrian) // Returns cached value.
console.log(specialNumPiper) // Returns cached value.

// Like above, we only get "Generating secret..." the first time. 
// The key difference here is, our cache variable is protected 
// inside of our closure and can't be accessed 
// from the outside.

I hope you can see how closures combined with memoization can be a powerful combination. We’re making the function run faster, by returning the cached value. At the same time, we’re also safeguarding our cache by using a closure.

An awesome tool to have in the belt, I’d say!