Open xianzao opened 1 year ago
原理上只用把参数和对应的结果数据存到一个对象中,调用时,判断参数对应的数据是否存在,存在就返回对应的结果数据。
// 第一版 (来自《JavaScript权威指南》)
function memoize(f) {
var cache = {};
return function(){
var key = arguments.length + Array.prototype.join.call(arguments, ",");
if (key in cache) {
return cache[key]
}
else {
return cache[key] = f.apply(this, arguments)
}
}
}
验证下:
var add = function(a, b, c) {
return a + b + c
}
var memoizedAdd = memoize(add)
console.time('use memoize')
for(var i = 0; i < 100000; i++) {
memoizedAdd(1, 2, 3)
}
console.timeEnd('use memoize')
console.time('not use memoize')
for(var i = 0; i < 100000; i++) {
add(1, 2, 3)
}
console.timeEnd('not use memoize')
因为第一版使用了 join 方法,当参数是对象的时候,就会自动调用 toString 方法转换成[Object object]
,再拼接字符串作为 key 值。我们写个 demo 验证一下这个问题:
var propValue = function(obj){
return obj.value
}
var memoizedAdd = memoize(propValue)
console.log(memoizedAdd({value: 1})) // 1
console.log(memoizedAdd({value: 2})) // 1
这里参考 underscore
的 memoize
函数:
// 第二版 (来自 underscore 的实现)
var memoize = function(func, hasher) {
var memoize = function(key) {
var cache = memoize.cache;
var address = '' + (hasher ? hasher.apply(this, arguments) : key);
if (!cache[address]) {
cache[address] = func.apply(this, arguments);
}
return cache[address];
};
memoize.cache = {};
return memoize;
};
从这个实现可以看出,underscore 默认使用 function 的第一个参数作为 key,所以如果直接使用
var add = function(a, b, c) {
return a + b + c
}
var memoizedAdd = memoize(add)
memoizedAdd(1, 2, 3) // 6
memoizedAdd(1, 2, 4) // 6
如果要支持多参数,我们就需要传入 hasher 函数,自定义存储的 key 值。所以我们考虑使用 JSON.stringify
:
var memoizedAdd = memoize(add, function(){
var args = Array.prototype.slice.call(arguments)
return JSON.stringify(args)
})
console.log(memoizedAdd(1, 2, 3)) // 6
console.log(memoizedAdd(1, 2, 4)) // 7
定义 函数记忆是指将上次的计算结果缓存起来,当下次调用时,如果遇到相同的参数,就直接返回缓存中的数据。
举个例子: