闭包通过持久化外部变量(如缓存对象)实现函数缓存,使内部函数能查存结果避免重复计算;memoize 工具用 map 存储单参数映射,适用于纯函数,但需注意内存泄漏、引用类型键及异步失效等问题。

闭包是实现函数缓存(Memoization)的核心机制,它让函数能“记住”之前计算过的输入与结果,避免重复执行耗时操作。
闭包如何支撑缓存逻辑
闭包使内部函数可以访问并持久化外部函数作用域中的变量(比如一个缓存对象)。每次调用被缓存的函数时,先查缓存,命中则直接返回;未命中则执行原函数、存入缓存再返回结果。这个缓存对象不会被垃圾回收,因为它始终被内部返回的函数引用着。
简易 memoize 工具函数
以下是一个通用、轻量的 memoize 实现:
function memoize(fn) {
const cache = new Map();
return function(arg) {
if (cache.has(arg)) {
return cache.get(arg);
}
const result = fn(arg);
cache.set(arg, result);
return result;
};
}
- 使用 Map 而非普通对象,支持任意类型键(如函数、对象、Symbol)
- 适用于纯函数:相同输入恒得相同输出,且无副作用
- 注意:只处理单个参数;多参数需序列化(如 JSON.stringify([...args]))或用更健壮的库(如 lodash.memoize)
实际应用示例
比如优化斐波那契数列递归:
const fib = memoize(n => n <p>再如封装 API 请求(需配合 Promise 缓存):</p><pre class="brush:php;toolbar:false;">const fetchUser = memoize(id =>
fetch(`/api/users/${id}`).then(r => r.json())
);
- 首次调用 fetchUser(123) 发起请求并缓存 Promise
- 后续调用直接返回同一 Promise,自动共享响应结果
- 注意:不适用于需要实时数据的场景(如用户状态轮询)
注意事项与边界情况
闭包缓存不是万能的,需警惕以下问题:
- 内存泄漏:缓存持续增长,尤其键不可控时(如时间戳、随机 ID),建议加容量限制或 LRU 策略
- 引用类型参数:{a:1} 和 {a:1} 是不同对象,Map 默认用 === 判断,需手动序列化或使用结构相等判断
- 异步缓存失效:Promise 缓存后无法主动清除,若需刷新,应暴露 clear 方法或使用带 TTL 的方案
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











