Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

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?

share|improve this question

2 Answers 2

I just thought about 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.

share|improve this answer
    
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 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
* by @philogb and @addyosmani
* 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);
    };
}

Source: Faster JavaScript Memoization For Improved Application Performance

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

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.