JavaScript记忆化高阶函数通过缓存参数与结果实现性能优化:基础版用JSON.stringify生成key适用于原始类型;增强版需处理对象、函数等复杂类型;LRU版本限制缓存大小防内存泄漏;注意this绑定、异步函数及副作用问题。

用 JavaScript 实现记忆化(memoization)高阶函数,核心是让目标函数“记住”之前算过的输入和对应结果,避免重复计算。关键在于:封装原函数、用缓存对象存结果、对参数做可键化处理(尤其是引用类型)、返回新函数。
基础版:只支持简单参数(如数字、字符串)
适用于参数全是原始值(primitive)的场景,可直接用 JSON.stringify 或模板字符串生成缓存 key:
function memoize(fn) {
const cache = new Map();
return function(...args) {
const key = JSON.stringify(args); // 简单参数可这样生成 key
if (cache.has(key)) {
return cache.get(key);
}
const result = fn.apply(this, args);
cache.set(key, result);
return result;
};
}
<p>// 使用示例
const fib = memoize(n => n <= 1 ? n : fib(n - 1) + fib(n - 2));
console.log(fib(10)); // 快速返回 55
增强版:支持对象/数组等复杂参数
原始值能 JSON 序列化,但函数、undefined、Symbol、Date、RegExp 等会丢失或报错。更健壮的做法是用唯一 ID 标识每个参数,比如用 WeakMap 做参数到 key 的映射,或借助第三方库(如 lodash 的 _.memoize 配合自定义 resolver)。简易可靠方案是使用 args.map(arg => arg && typeof arg === 'object' ? Object.prototype.toString.call(arg) : String(arg)).join('|'),但仍有局限。生产环境推荐:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 用
JSON.stringify+try/catch回退到String(arg) - 对常见内置对象(Date、RegExp、Array、Object)手动标准化
- 接受一个自定义
resolver函数,由用户决定如何生成 key
带清理能力的版本(LRU 缓存)
无限缓存可能造成内存泄漏。可用 Map 实现 LRU(最近最少使用),限制最大条目数:
立即学习“Java免费学习笔记(深入)”;
function memoizeLRU(fn, max = 100) {
const cache = new Map();
return function(...args) {
const key = JSON.stringify(args);
if (cache.has(key)) {
// 移动到末尾(最新使用)
const value = cache.get(key);
cache.delete(key);
cache.set(key, value);
return value;
}
const result = fn.apply(this, args);
if (cache.size >= max && max > 0) {
// 删除第一个(最久未用)
cache.delete(cache.keys().next().value);
}
cache.set(key, result);
return result;
};
}
注意事项与边界情况
-
this 绑定:上面实现保留了调用时的
this,但若原函数依赖特定上下文,建议明确传入或用fn.call(this, ...args) - 异步函数:普通 memoize 不适合 Promise 返回值;需单独处理(缓存 Promise 实例本身,而非 await 后结果)
- 副作用函数:有副作用(如修改全局状态、发请求)的函数不应盲目 memoize
-
浅比较陷阱:
{a:1}和{a:1}是两个对象,JSON.stringify 后相同才有效;若参数是同一对象引用,缓存才命中

















