封装带缓存的闭包工厂应明确缓存职责分离,通过可选参数传入缓存策略,稳定生成键,支持生命周期控制与内存安全(如weakmap),并提供.clear()等辅助方法,确保缓存透明、可控、无泄漏。

封装一个带缓存的闭包工厂,核心在于让工厂函数返回的闭包能复用计算结果,同时保持调用接口简洁、缓存策略可控、内存不泄漏。关键不是堆砌装饰器或类,而是厘清“谁负责缓存”“缓存存什么”“何时失效”。
缓存逻辑与闭包职责要分离
闭包本身应专注业务逻辑,缓存由外部统一管理。推荐把缓存作为可选参数传入工厂,而非硬编码在闭包内部。这样便于测试、替换策略(如 LRU、TTL)、甚至禁用缓存做对比验证。
- 工厂函数接收一个 cacheMap(如 Map 或 WeakMap),或一个缓存策略对象(含 get/set/delete 方法)
- 闭包内部只调用 cache.get(key) 和 cache.set(key, value),不感知实现细节
- 若未传缓存,则默认使用空操作对象(noop cache),保证接口一致性
键生成必须稳定且可预测
缓存命中依赖 key 的一致性。简单 JSON.stringify(arguments) 容易出错(函数、undefined、Symbol、循环引用)。更稳妥的方式是显式定义参数签名规则。
- 对基础类型参数(string/number/boolean/null),可用 Array.from(arguments).join('||') 作简易 key
- 对对象参数,建议只取其用于计算的**确定性字段**拼接,例如
user.id + '_' + mode - 避免直接序列化整个参数对象;必要时用 JSON.stringify(omit(obj, ['meta', 'callback'])) 过滤不稳定字段
支持缓存生命周期控制
静态缓存(永久)适合纯函数;但多数场景需要过期或按需清除。可在工厂返回的闭包上挂载辅助方法,不破坏调用语义。
- 返回的闭包自带 .clear() 方法,清空所属缓存
- 支持 .getCacheKey(...args) 供外部调试或预热使用
- 若使用 TTL 缓存,工厂可接受 ttlMs 参数,自动包装带时间戳的缓存逻辑
兼顾内存安全与弱引用场景
当闭包处理大量临时对象(如 DOM 节点、大型配置),用 WeakMap 做缓存可避免内存泄漏;但 WeakMap 不支持遍历和 clear,需配合额外管理。
- 对“键是对象”的场景,优先用 WeakMap,确保对象销毁后缓存自动回收
- 若需手动清理,可搭配 FinalizationRegistry(现代环境)或退化为 Map + 显式 .dispose() 约定
- 工厂内部不做强引用假设,所有缓存操作都通过抽象接口,方便运行时切换
不复杂但容易忽略:缓存不是加了就快,而是加得准、清得稳、看得见。真正优雅的封装,是让缓存像空气一样存在——用时有效,查时透明,不用时不碍事。











