Reputation: 3415
_.memoize = function(func) {
var cached = {};
return function() {
var args = Array.prototype.slice.call(arguments);
if (cached[args]) {
console.log('returning cached');
return cached[args];
} else {
cached[args] = func.apply(this, args);
return cached[args];
}
};
};
_.memoize = function(func) {
var cached = {};
return function() {
if (cached[arguments]) {
console.log('returning cached');
return cached[arguments];
} else {
cached[arguments] = func.apply(this, arguments);
return cached[arguments];
}
};
};
var add = function(a, b) {
return a + b;
};
var memoAdd = _.memoize(add);
memoAdd(1, 2) => 3;
memoAdd(3, 4)
'returning cached'
=> 3; ????
Why does the second memoize implementation not work without the Array.prototype.slice.call?
is the bracket notation actually stringifying the word arguments as a key instead of the actual real arguments?
Upvotes: 0
Views: 1114
Reputation: 3315
The arguments is an object and not an array.
The arguments object is not an Array. It is similar to an Array, but does not have any Array properties except length.
So when you run memoization with your second implementation, you will see this in your cached
variable :
Cached = {} //Empty cache
(index):56 Arguments = [object Arguments] //Arguments is an object
(index):57 Is Array = false //Not an array
(index):74 3
//Will set the object as key, not an array
(index):55 Cached = {"[object Arguments]":3}
(index):56 Arguments = [object Arguments]
(index):57 Is Array = false
//because it will still access to cached[[object ...]]
(index):59 returning cached
(index):76 3
So it will always set and access to the key [object Arguments]
, due to the stringification
.
So, you have to use the first implementation, by using the Array.prototype.slice.call which will convert to a real Array.
Then, after stringification you will get :
Cached = {}
(index):39 Arguments = 1,2 //Is an array as you can see
(index):40 Is Array = true
(index):74 3
//Set an array as key
(index):38 Cached = {"1,2":3}
//Key 3,4 is not in the cached variable, you can continue
(index):39 Arguments = 3,4
(index):40 Is Array = true
(index):76 7
Upvotes: 0
Reputation: 106027
is the bracket notation actually stringifying the word arguments as a key instead of the actual real arguments?
Close, but not quite. You're right that a difference in stringification is involved. arguments
, as you may or may not know, isn't an Array, it's a special Arguments object. This is inconvenient for a few reasons, but the one that's relevant here can be illustrated thusly:
function argsObj() {
var obj = {};
var args = Array.prototype.slice.call(arguments);
obj[arguments] = 1;
obj[args] = 2;
return obj;
}
console.log(argsObj(123, 456, 789));
// => { "[object Arguments]": 1,
// "123,456,789": 2
// }
When an Arguments object is "stringified" to be used as a property name we always get [object Arguments]
. If we want the property name to actually reflect the arguments themselves—which we need for memoization—we have to convert the Arguments object to an Array first, which is what Array.prototype.slice.call(arguments)
does.
P.S. Even with Array.prototype.slice
this memoization scheme has a big weakness. See what happens when you try it with arguments that are objects, or even arrays.
Upvotes: 1