I\'m struggling with an example of js memoization found on a book, here\'s the code:
Function.prototype.memoized = function(key){
this._values = this._va
Let's use a simple example, fibonacci numbers.
function fib(n) {
if (n < 2) return 1;
return fib.memoized(n-1) + fib.memoized(n-2);
}
Here we can see that the memoized
method is applied on the fib
function, i.e. your this keyword refers to the fib
function. It does not relaunch the memoized
function, but "launches" the function on which it was called. However, it does call it with this
set to the function itself, which does not make any sense. Better:
Function.prototype.memoize = function(key){
if (!this._values)
this._values = {};
if (key in this._values)
return this._values[key];
else
return this._values[key] = this.apply(null, arguments);
// pass null here: ^^^^
}
Even better would be if memoized
would return a closure:
Function.prototype.memoized = function(v) {
var fn = this, // the function on which "memoized" was called
values = v || {};
return function(key) {
if (key in values)
return values[key];
else
return values[key] = fn.apply(this, arguments);
}
}
var fib = function(n) {
if (n < 2) return 1;
return fib(n-1) + fib(n-2);
}.memoized();
// or even
var fib = function(n) { return fib(n-1) + fib(n-2) }.memoized({0:1, 1:1});
Notes
Since you are attaching memoized
to the Function.prototype
, you can invoke this memoized
on some other function only. Like in your example
isPrime.memoized(5)
Since you are invoking memoized
on a function, the this
will be referring to the function on which the memoized
is invoked. So, in this case, this
refers to isPrime
.
Actual explanation
this._values = this._values || {};
This line makes sure that the isPrime
has got an attribute with the name _values
and it should have an empty object, if it is not there already.
this._values[key] !== undefined
This check is to make sure that we have been already called with key
or not. If the value is not undefined
, then return this._values[key]
.
Otherwise,
this._values[key] = this.apply(this, arguments)
store the result of calling this.apply(this, arguments)
in this._values[key]
and return it. Now the important part.
this.apply(this, arguments)
It is straight forward. arguments
is an array like object. So, If you have actually called isPrime
like this isPrime(1, 2, 3, 4)
, arguments will have {'0': 1, '1': 2, '2': 3, '3': 4}
. Now that we are inside memoized
, we need to invoke isPrime
as it was intended to be invoked. So, this.apply(this, arguments)
is done. Function.prototype.apply
, tries to spread the array like object passed as the second parameter, while invoking the function.