函数记忆是一种编程技巧,通过牺牲算法的空间复杂度以换取更优的时间复杂度 记忆化(memoization)是一种构建函数的处理过程,能够记住上次计算结果
1. 定义:
自记忆函数其实就是能够记住上次计算结果的函数。
2.实现:
在实现中,我们可以这样进行处理:当函数计算得到结果时,就将该结果按照参数存储起来。采取这种方式时,如果另外一个调用也使用相同的参数,我们则可以直接返回上次存储的结果而不是再计算一遍。
显而易见,像这样避免既重复又复杂的计算可以显著提高性能。对于动画中的计算、搜索不经常变化的数据或任何耗时的数学计算来说,记忆化这种方式是十分有用的。
可以借助map对象、JSON.stringify()、闭包包装传递的函数,使其具有函数记忆的特性
例子1:
const add = () => {
const cache = {};
return num => {
if (num in cache) {
return `From cache! ${cache[num]}`;
} else {
const result = num + 10;
cache[num] = result;
return `Calculated! ${result}`;
}
};
};
const addFunction = add();
console.log(addFunction(10));
console.log(addFunction(10));
console.log(addFunction(5 * 2));
add
函数是一个记忆函数。 通过记忆化,我们可以缓存函数的结果,以加快其执行速度。上述情况,我们创建一个cache
对象,用于存储先前返回过的值。
如果我们使用相同的参数多次调用addFunction
函数,它首先检查缓存中是否已有该值,如果有,则返回缓存值,这将节省执行时间。如果没有,那么它将计算该值,并存储在缓存中。
我们用相同的值三次调用了addFunction
函数:
在第一次调用,num
等于10
时函数的值尚未缓存,if语句num in cache
返回false
,else块的代码被执行:Calculated! 20
,并且其结果被添加到缓存对象,cache
现在看起来像{10:20}
。
第二次,cache
对象包含10
的返回值。 if语句 num in cache
返回true
,From cache! 20
被打印。
第三次,我们将5 * 2
(值为10)传递给函数。 cache
对象包含10
的返回值。 if语句 num in cache
返回true
,From cache! 20
被打印。
例子2:
const memorize = (cb) => {
const cache = new Map();
return function() {
const key = JSON.stringify(arguments);
if (cache.has(key)) {
return cache.get(key)
} else {
const result = fn(arguments);
cache.set(key, result);
return result;
}
}
}
总结
自记忆函数有两个优点:
- 由于函数调用时会寻找之前调用所得到的值,所以用户最终会乐于看到所获得的性能收益。
- 它不需要执行任何特殊请求,也不需要做任何额外初始化,就能顺利进行工作。
但是,自记忆函数并不是完美的,它一样有着缺陷:
- 任何类型的缓存都必然会为性能牺牲内存。
- 很多人认为缓存逻辑不应该和业务逻辑混合,函数或方法只需要把一件事情做好。
- 对自记忆函数很难做负载测试或估算算法复杂度,因为结果依赖于函数之前的输入。