# Elegant memoizing

I wanted an elegant way to implement memoizing. Here is what I came up with:

function memoize(fn) {
var cache = new WeakMap();
return function() {
if (!cache[arguments]) {
cache[arguments] = fn.call(this, arguments);
}
return cache[arguments];
}
}


It's quite nice, but the WeakMap is not well supported. Is there a better, yet clean way to do this?

-

function memoize(fn) {
var cache = {};
return function() {
var args = Array.prototype.slice.call(arguments).toString();
if (!cache[args]) {
cache[args] = fn.call(this, arguments);
}
return cache[args];
}
}


It's very cross-browser. I can't think of any browser not supporting this.

But it does feel kind of ugly. It's still the best I can think of though.

-
This isn't equivalent. There can be collisions. For example, ["a,b"] and ["a", "b] (at least my understanding of Array.toString -- developer.mozilla.org/en-US/docs/JavaScript/Reference/…) –  Corbin Feb 1 '13 at 19:06
Indeed. Then I'm lost :P –  Florian Margaine Feb 1 '13 at 19:08
JSON stringifying would probably be wiser –  megawac Aug 15 '14 at 0:21

Is there a better, yet clean way to do this?

"Better" and "clean" are both debatable. There's a way to do it, using JSON serialization.

But speaking to your current code, I'm not sure that maps would the trick. Every call to the function will result in a distinct arguments object (even if the individual arguments are the same), so I think you'd get "duplicate" keys. At least I imagine so. I don't have an up-to-date browser on this machine, so I can't test, and I haven't played enough with Map/WeakMap to know off-hand.

Besides, you need to use has() and set(); using [...] will, I believe, just set a regular property (which implies string coercion of the key).

Now, for alternatives, you could do something like what Addy Osmani's proposes (the entire article is worth a read). The basic idea is to use JSON.stringify() to serialize the arguments in a more robust way than toString.

I'll include it here, as-is:

/*
* memoize.js
* with further optimizations by @mathias
* and @DmitryBaranovsk
* perf tests: http://bit.ly/q3zpG3
* Released under an MIT license.
*/
function memoize( fn ) {
return function () {
var args = Array.prototype.slice.call(arguments),
hash = "",
i = args.length;
currentArg = null;
while (i--) {
currentArg = args[i];
hash += (currentArg === Object(currentArg)) ?
JSON.stringify(currentArg) : currentArg;
fn.memoize || (fn.memoize = {});
}
return (hash in fn.memoize) ? fn.memoize[hash] :
fn.memoize[hash] = fn.apply(this, args);
};
}


It's a pretty neat solution, though obviously not as clean as just using WeakMap (if indeed that would even work).

-