I'm developing my own functional-programming library, and now referring the underscore
.
memoize _.memoize(function, [hashFunction])
Memoizes a given function by caching the computed result. Useful for speeding up slow-running computations. If passed an optional hashFunction, it will be used to compute the hash key for storing the result, based on the arguments to the original function. The default hashFunction just uses the first argument to the memoized function as the key.
var fibonacci = _.memoize(function(n) {
return n < 2 ? n: fibonacci(n - 1) + fibonacci(n - 2);
});
The above code that enables automatic memorisation without dealing array
looks sort of magic, and I saw the source-code below, but still the inner design is not clear to me.
// Memoize an expensive function by storing its results.
_.memoize = function(func, hasher) {
var memoize = function(key) {
var cache = memoize.cache;
var address = hasher ? hasher.apply(this, arguments) : key;
if (!_.has(cache, address)) cache[address] = func.apply(this, arguments);
return cache[key];
};
memoize.cache = {};
return memoize;
};
Can someone give me a brief idea of what is going on?
Appreciated.
memoize
has a cache
(memoize.cache = {}
) that uses for storing the result of the function call. When it's called, it determines an address
to store the result by two means: either a call to the hasher
function, or the key
parameter.
The hasher function works like this (from the underscore page):
If passed an optional hashFunction, it will be used to compute the
hash key for storing the result, based on the arguments to the
original function. The default hashFunction just uses the first
argument to the memoized function as the key.
Then, it calls the function you passed func.apply(...)
, and stores the result at cache[address]
.
The second time you call the memoized function, the result will already be in cache (!_.has(..)
will return false
) and the computation won't be repeated.
I dont' understand why it returns cache[key]
and not cache[address]
tough...seems to me that cache[address]
would be the correct choice.
Update
As pointed out in the comments, the code you present is not the latest implementation of memoize
. This is the latest implementation (1.6.0):
_.memoize = function(func, hasher) {
var memo = {};
hasher || (hasher = _.identity);
return function() {
var key = hasher.apply(this, arguments);
return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
};
};
It works the same way, except from the fact that it is a little more elegant; if an hasher
function it's not provided, it uses _.identity
as a key, that is a function that simply returns the value passed as an argument:
_.identity = function(value) { return value; }
Aside from this, cache
is now called memo
but works the same way.