如何实现支持所有参数类型的通用memoize缓存函数?
支持任意类型参数的通用memoize函数实现
原有实现的问题
你现有的实现直接把args参数数组作为Map的key,而Map的键匹配基于*严格相等(===)*规则:每次调用传入的匿名函数、字面量数组、字面量对象都是独立的新引用,和之前的参数引用不相等,自然无法命中缓存。
核心实现思路
要实现按值匹配引用类型的缓存能力,需要把所有参数转换成可按值比较的特征缓存键,核心逻辑如下:
- 原始值类型直接用原值+类型作为特征
- 函数提取
toString()的函数体内容作为特征 - 数组、普通对象递归序列化所有属性/元素作为特征
- 额外处理循环引用、Date、RegExp等特殊类型的特征提取
完整实现代码
// 辅助函数:将任意类型值序列化为可比较的特征字符串 function serializeValue(value, seen = new WeakSet()) { // 处理原始值类型 if (typeof value !== 'object' && typeof value !== 'function') { return `${typeof value}:${value}` } // 处理null if (value === null) return 'null' // 处理函数 if (typeof value === 'function') { return `function:${value.toString()}` } // 处理循环引用避免爆栈 if (seen.has(value)) { return '[Circular Reference]' } seen.add(value) // 处理数组 if (Array.isArray(value)) { return `array:[${value.map(item => serializeValue(item, new WeakSet(seen))).join(',')}]` } // 处理日期对象 if (value instanceof Date) { return `date:${value.getTime()}` } // 处理正则对象 if (value instanceof RegExp) { return `regexp:${value.toString()}` } // 处理普通对象,按key排序避免属性顺序不同导致匹配失败 const sortedKeys = Object.keys(value).sort() const objContent = sortedKeys.map(key => `${key}:${serializeValue(value[key], new WeakSet(seen))}`).join(',') return `object:{${objContent}}` } function memoize(expensivefn) { const cache = new Map() return function(...args) { // 生成参数对应的唯一缓存键 const cacheKey = args.map(arg => serializeValue(arg)).join('|') if (cache.has(cacheKey)) { return cache.get(cacheKey) } const result = expensivefn(...args) cache.set(cacheKey, result) return result } }
使用效果验证
你提供的所有测试用例使用上述实现运行,都可以符合预期命中缓存:
- 两次传入相同内容的匿名函数不会重复执行原函数
- 两次传入值相等的数组、对象可以直接读取缓存结果
- 命名函数的缓存逻辑保持正常
可选优化点
- 如果你需要支持Map、Set等更多内置类型,可以在
serializeValue中扩展对应的判断和特征提取逻辑 - 如果需要忽略函数定义的空格、换行等格式差异,可以对函数的
toString()结果做格式化后再生成特征 - 如果你需要限制缓存大小避免内存溢出,可以搭配LRU淘汰策略替换原生Map
内容的提问来源于stack exchange,提问作者Sanjeet kumar
相关产品推荐
相关产品推荐

