闭包缓存函数结果的核心是利用闭包创建私有持久化缓存空间,用map存储任意类型键的计算结果,通过json.stringify参数生成唯一键,并确保纯函数前提、this绑定及错误处理。

用闭包缓存函数结果,核心是让函数“记住”自己算过的值,下次相同输入直接返回,跳过重复计算。这不是加个装饰器就完事,关键在缓存怎么存、键怎么定、边界怎么控。
闭包提供私有且持久的缓存空间
闭包天然适合做这件事——外层函数定义一个缓存容器(比如 Map),内层函数通过作用域链持续访问它。这个缓存不会被垃圾回收,也不被外部干扰,每个 memoize(fn) 调用都生成独立缓存实例。
- 用 Map 而不是普通对象:支持任意类型键(数字、字符串、对象、函数),避免
toString()冲突或原型污染 - 缓存变量声明在闭包内,外部无法直接读写,封装性强
- 返回的新函数始终持有对缓存的引用,状态得以维持
参数要能稳定转成唯一缓存键
缓存是否命中,取决于键是否一致。原始参数(尤其是对象、数组)不能直接当键用,必须序列化或归一化。
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 单个基础类型参数(如数字、字符串)可直接作为 Map 键,无需处理
- 多个参数或含对象时,推荐
JSON.stringify([a, b, c]),简单场景够用 - 遇到
undefined、function、Symbol或循环引用,JSON.stringify会丢失或报错,此时需改用structuredClone(现代环境)或轻量比较库(如fast-deep-equal) - 键生成逻辑必须确定:相同输入永远产出相同字符串,顺序、字段名、嵌套结构都要一致
得兼顾纯函数前提和常见陷阱
缓存只对纯函数有效——输入相同,输出一定相同,且不修改外部状态。
-
别缓存副作用函数:比如
fetch、console.log、DOM 操作,除非你明确控制执行时机(如 Promise 缓存防重复请求) -
this 绑定要保留:用
fn.apply(this, args)或fn.call(this, ...args),否则上下文丢失 - Promise 缓存的是实例本身:后续调用拿到同一 Promise,自动共享 resolve/reject 状态,适合防抖请求,但不支持主动刷新
-
内存得管住:长期运行时缓存可能无限增长,建议引入 LRU 机制(如用
lru-cache替代原生 Map)或暴露clear()方法
一个稳妥可用的基础实现
下面这个版本支持多参数、保留 this、用 Map、带基本错误防护:
function memoize(fn) {
const cache = new Map();
return function(...args) {
const key = JSON.stringify(args);
if (cache.has(key)) {
return cache.get(key);
}
try {
const result = fn.apply(this, args);
cache.set(key, result);
return result;
} catch (e) {
cache.set(key, { error: e }); // 缓存错误避免重抛
throw e;
}
};
}
使用示例:
const expensiveCalc = memoize((a, b) => {
console.log('running...');
return a * b + Math.sin(a);
});
<p>expensiveCalc(2, 3); // 打印 'running...',返回结果
expensiveCalc(2, 3); // 不打印,直接返回缓存结果</p>Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










