要创建一个记忆化函数,核心是通过缓存避免重复计算,提升性能。1. 实现记忆化需创建高阶函数,接收原函数并返回带缓存逻辑的包装函数;2. 使用 map 存储参数与结果的映射,通过 json.stringify(args) 生成键,但需注意属性顺序、循环引用等问题;3. 对于非原始类型参数,json.stringify 有局限,可采用自定义序列化、哈希函数或 weakmap 优化;4. 必须使用 apply 或 call 保留原函数 this 上下文;5. 记忆化适用于纯函数,如递归算法、昂贵计算、稳定 api 调用等场景;6. 需警惕副作用函数不适用、内存泄漏、缓存键不一致和缓存过期等问题。因此,记忆化是性能优化的有效手段,但需权衡适用性与开销,确保正确使用才能发挥其最大价值。

JavaScript 中,要创建一个记忆化(memoized)函数,核心思路就是给一个函数加上缓存层。这意味着当函数被调用时,它会先检查之前是否用相同的参数调用过。如果答案是肯定的,它就直接返回之前计算并存储的结果,而不是重新执行函数本身。这样能显著提升性能,尤其对于那些计算成本高昂或者会频繁重复调用的函数来说。
实现一个记忆化函数,通常我们会创建一个高阶函数(higher-order function),它接受一个原始函数作为参数,然后返回一个包装了缓存逻辑的新函数。下面是一个基础的
memoize
function memoize(func) {
const cache = new Map(); // 使用 Map 作为缓存,键可以是任何值,包括对象
return function(...args) {
// 将参数转换为一个唯一的键。这里简单地用 JSON.stringify,但要注意它的局限性
const key = JSON.stringify(args);
if (cache.has(key)) {
console.log(`从缓存中获取结果: ${key}`);
return cache.get(key);
}
// 如果缓存中没有,则调用原始函数,并存储结果
console.log(`计算结果并存入缓存: ${key}`);
const result = func.apply(this, args); // 确保原始函数的 this 上下文被保留
cache.set(key, result);
return result;
};
}
// 示例:一个模拟耗时计算的函数
function expensiveCalculation(num1, num2) {
console.log(`正在执行耗时计算: ${num1}, ${num2}...`);
// 模拟耗时操作,例如复杂的数学运算或网络请求
let sum = 0;
for (let i = 0; i < 100000000; i++) {
sum += Math.sqrt(i);
}
return num1 + num2 + sum;
}
// 创建记忆化版本的函数
const memoizedCalculation = memoize(expensiveCalculation);
console.log(memoizedCalculation(10, 20)); // 第一次调用,会执行计算
console.log(memoizedCalculation(10, 20)); // 第二次调用,直接从缓存获取
console.log(memoizedCalculation(5, 15)); // 第一次调用,会执行计算
console.log(memoizedCalculation(10, 20)); // 第三次调用,再次从缓存获取这个
memoize
cache
memoizedCalculation
key
key
cache
expensiveCalculation
cache
说实话,我个人在写代码的时候,遇到性能瓶颈,记忆化函数经常是我的“救火队员”之一。它的重要性主要体现在几个方面:
首先,最直观的就是性能提升。设想一下,你有一个递归函数,比如计算斐波那契数列,如果不用记忆化,每次都会重复计算大量的子问题。举个例子,计算
fib(5)
fib(4)
fib(3)
fib(4)
fib(3)
fib(2)
fib(3)
fib(3)
其次,它能减少不必要的资源消耗。这不仅仅是CPU时间,还可能是网络请求、数据库查询或者文件读写。比如一个函数需要从远程API获取数据,如果数据在短时间内不会变化,我们完全可以记忆化这个函数。这样,后续对相同参数的调用就不用再发起网络请求了,直接从内存里拿,响应速度自然就快了。这对于用户体验来说,简直是质的飞跃。
再者,对于纯函数来说,记忆化简直是天作之合。一个纯函数,只要输入相同,输出就必然相同,而且没有副作用。这种特性让记忆化变得非常安全和可靠。你不需要担心缓存的结果会因为外部状态的变化而变得不准确。所以,在设计函数时,如果能让它们保持纯粹,那么在需要优化性能时,记忆化就成了一个非常自然的选项。在我看来,它就是那种“小投入大回报”的优化手段。
记忆化函数确实是个好东西,但它也不是万能药,有它擅长的领域,也有它力不从心的地方。
常见的应用场景:
React.memo
useMemo
需要注意的限制:
JSON.stringify
undefined
总的来说,记忆化是把双刃剑。用得好,性能飞升;用不好,可能引入新的bug或者内存问题。在决定使用它之前,最好先评估一下函数的特性以及它可能带来的开销。
嗯,这确实是记忆化函数里比较“烧脑”的部分,尤其当参数不再是简单的数字或字符串时。我经常在这个地方纠结,因为处理不好就可能导致缓存失效或者性能反而下降。
1. 处理多参数:
对于多个原始类型参数,比如
func(a, b, c)
key =
更通用的做法,就像上面示例里用的
JSON.stringify(args)
// 简单拼接
const key = args.join('_'); // 适用于参数都是原始类型,且不含下划线等特殊字符的情况
// JSON.stringify
const key = JSON.stringify(args); // 更通用,但有局限性2. 处理非原始类型参数(对象、数组、函数等):
这是真正的挑战所在。
JSON.stringify
{a: 1, b: 2}{b: 2, a: 1}JSON.stringify
JSON.stringify
undefined
JSON.stringify
undefined
JSON.stringify
更高级的键生成策略:
自定义序列化函数:你可以编写一个更智能的函数来将参数“规范化”为键。例如,可以对对象属性进行排序,确保顺序一致;或者只提取对象中对函数结果有影响的关键属性来生成键。这需要根据具体业务逻辑来定,没有银弹。
哈希函数:使用一个稳定的哈希函数来生成参数的哈希值作为键。这比
JSON.stringify
WeakMap:如果你的缓存键是对象,并且你希望当这些对象不再被其他地方引用时,它们能被垃圾回收,那么
WeakMap
WeakMap
WeakMap
function memoizeWithWeakMap(func) {
const cache = new WeakMap(); // 外层 WeakMap 缓存第一个参数
return function(objArg, ...restArgs) {
// 如果第一个参数不是对象,这种方式就不太适用
if (typeof objArg !== 'object' || objArg === null) {
// 回退到其他键生成方式或直接不缓存
const key = JSON.stringify([objArg, ...restArgs]);
// ...这里需要一个Fallback机制或者报错
return func.apply(this, [objArg, ...restArgs]);
}
let innerMap = cache.get(objArg);
if (!innerMap) {
innerMap = new Map();
cache.set(objArg, innerMap);
}
// 对剩余参数生成键
const restKey = JSON.stringify(restArgs);
if (innerMap.has(restKey)) {
return innerMap.get(restKey);
}
const result = func.apply(this, [objArg, ...restArgs]);
innerMap.set(restKey, result);
return result;
};
}这种嵌套
WeakMap
Map
保留 this
memoize
func
func.apply(this, args)
func.call(this, ...args)
this
this
总的来说,处理非原始类型参数的记忆化,没有一个放之四海而皆准的完美方案。很多时候,这需要你深入理解业务逻辑,判断哪些参数是真正影响结果的,然后为这些关键参数设计一个高效且稳定的键生成策略。如果参数的复杂性使得键生成变得非常昂贵或不可靠,那么可能记忆化就不是最好的选择了,或者需要引入更专业的缓存库来管理。我个人的经验是,对于简单的场景,内置的
Map
JSON.stringify
以上就是js 怎么用memoize创建记忆化函数的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号