「前端每日一问(31)」如何用闭包设计一个缓存模块?

432 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

本题难度:⭐ ⭐

答:

闭包的作用是创造私有变量,且延长私有变量的生命周期,这样的特性可以用来做缓存模块,让私有变量当成缓存一直驻扎在内存中,直到页面被销毁。

下面,我用两个例子来列举如何用闭包实现一个缓存模块。

例1 缓存耗时的计算

假设有一个计算非常耗时,需要设计一个缓存模块把计算结果存起来,下次计算前先看一下缓存里有没有值,有值就直接返回,就这样就不用每次重新计算了。

我们用计算素数来模拟一个非常耗时的计算,计算素数的代码如下:

function isPrime (n) {
  let res = n > 1

  for (let i = 2; i < n; i++) {
    if (n % i === 0) {
      res = false
      break
    }
  }
  
  return res
}

console.log(isPrime(2)) // true
console.log(isPrime(3)) // true
console.log(isPrime(4)) // false
console.log(isPrime(5)) // true

接下来,用一个 cache 对象来缓存计算结果,如果 cache 中没有值就存进去,cache 中有值就直接返回。

const cache = {}

function isPrime (n) {
  if (n in cache) {
    console.log(`cache中有${n},直接返回 :>> `, cache[n])
    return cache[n]
  }

  let res = n > 1

  for (let i = 2; i < n; i++) {
    if (n % i === 0) {
      res = false
      break
    }
  }

  console.log(`cache中没有${n},存进去 :>> `, res)
  cache[n] = res

  return res
}

测试一下:

isPrime(3)
isPrime(4)
isPrime(5)
isPrime(5)
isPrime(5)

console.log('cache :>> ', cache)

image.png

以上代码虽然可以实现缓存功能,但是最大的问题就是缓存需要定义一个全局变量 cache。

这个时候,闭包出现了,其实这个 cache 变量是可以用闭包隐藏的。

把 cache 定义到一个匿名函数内,在这个匿名函数内部返回计算素数的函数,这样就可以在外部调用计算素数的函数,而且 cache 对象就被藏到了闭包里,全局访问不到 cache 对象,代码如下:

const isPrime = (function () {
  const cache = {}

  return function (n) {
    if (n in cache) {
      console.log(`cache中有${n},直接返回 :>> `, cache[n])
      return cache[n]
    }

    let res = n > 1
    
    for (let i = 2; i < n; i++) {
      if (n % i === 0) {
        res = false
        break
      }
    }

    console.log(`cache中没有${n},存进去 :>> `, res)
    cache[n] = res

    return res
  }
})()

isPrime(3)
isPrime(4)
isPrime(5)
isPrime(5)
isPrime(5)

image.png

例2 仿 localStorage

实现一个简单的类似于 localStorage 的功能,可以通过 set 方法存值,get 方法取值。

原理和例1一样,都是把 cache 定义到一个匿名函数内部。

这个匿名函数返回一个对象,在对象上有缓存模块的 get 和 set 方法,通过 set 方法把数据存到匿名函数内部的 cache 对象上,通过 get 方法读取数据。

const myStorage = (function () {
  const cache = {}
  return {
    set: (key, val) => {
      cache[key] = val
    },
    get: (key) => {
      if (key in cache) {
        return cache[key]
      }
    }
  }
})()

myStorage.set('name', 'lin')
myStorage.set('age', 18)

console.log(myStorage.get('name'))
console.log(myStorage.get('age'))

image.png

结尾

如果我的文章对你有帮助,你的👍就是对我的最大支持^_^

你也可以关注《前端每日一问》这个专栏,防止失联哦~

我是阿林,输出洞见技术,再会!

上一篇:

「前端每日一问(30)」闭包和立即执行函数IIFE的关系

下一篇:

「前端每日一问(32)」如何用闭包实现一个单例模式?