The following is from John Hann's implementation, and this code caught my attention, which cached the result of the method call with clever methods.
Code parsing:
The code copy is as follows:
// memoize: a common method to use memoization to cache
// func: Method to be cached
// context: Method execution context
// Note: The method must be externally accessible, and the parameters are character-serialized
function memoize (func, context) {
function memoizeArg (argPos) { //The parameter indicates the position of the parameter in the original method
var cache = {}; //The key of this cache is the parameter, and the value is the execution result
return function () { //Return a function closure
if (argPos == 0) { //The first parameter, if the parameter does not exist in the cached key, the original function will be executed and the execution result will be stored
if (!(arguments[argPos] in cache)) {
cache[arguments[argPos]] = func.apply(context, arguments);
}
return cache[arguments[argPos]];
}
else { //Not the first parameter. If the parameter does not exist in the cached key, the memoizeArg method will be executed recursively. The position of the parameter in the original method -1
if (!(arguments[argPos] in cache)) {
cache[arguments[argPos]] = memoizeArg(argPos - 1);
}
return cache[arguments[argPos]].apply(this, arguments);
}
}
}
var arity = func.arity || func.length; //The length of the func parameter is used, and the arity attribute is used in javascript.
return memoizeArg(arity - 1); //Recursion starts from the last parameter
}
use:
The code copy is as follows:
var mem = memoize(func, this);
alert(mem.call(this,1,1,2));
alert(mem.call(this,2,1,2));
alert(mem.call(this,3,1,3));
alert(mem.call(this,2,2,4));
It seems simple, but it doesn't seem easy to understand when you look at it, but if you are familiar with the use of closures, it will be easy to understand. After the above calls to mem.call, a tree is formed. Each node is a closure, each closure has a cache, and each cache key is a tree branch:
(Note: The "result" in the picture above is also a closure, but argPos is only 0)
But there are many ways, such as limboy said:
The code copy is as follows:
function Memoize(fn){
var cache = {};
return function(){
var key = [];
for( var i=0, l = arguments.length; i < l; i++ )
key.push(arguments[i]);
if( !(key in cache) )
cache[key] = fn.apply(this, arguments);
return cache[key];
};
}
The implementation is easier, but push the parameters into an array and then treat the array as a key, and the key only supports string type. Therefore, you need to pay attention to this point when using it (for example, after an object tostring, you may only see "[object Object]"), and its function is weaker than the above one.
It is not difficult to improve this. Just set up another object with the parameter, and the original cache object and this other parameter object are associated with the ID:
The code copy is as follows:
function Memoize(fn){
var cache = {}, args = {};
return function(){
for( var i=0, key = args.length; i < key; i++ ) {
if( equal( args[i], arguments ) )
return cache[i];
}
args[key] = arguments;
cache[key] = fn.apply(this, arguments);
return cache[key];
};
}
There are some other methods that can be written as concise functional methods.