HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Elegant memoizing

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
memoizingelegantstackoverflow

Problem

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?

Solution

I use this

function memoizeFirst(fn) {
    const cache = new WeakMap();
    return function(arg) {
        if (!cache.has(arg)) {
            cache.set(arg, fn(arg));
        }
        return cache.get(arg);
    };
}


this function will memoize the result of the function you pass and cache it. The cache will vary on the first argument, and only on the first argument. Do not use this function if you are planning on passing more then one argument to it! Do use this function if you want to pass an object as the first argument.

I use this function for building (temporary) indexes based on an immutable state. Example (the groupBy, where methods come from IxJS):

const getParentObjectIndex = memoizeFirst(state => state.objectSource && state.objectSource.
    where(objectItem => objectItem.parentObject).
    groupBy(objectItem => objectItem.parentObject).
    reduce(function(map, group) {
        map[group.key] = group.
        orderBy(item => item.position).
        toArray();
        return map;
    }, {})
);


Because the state is immutable, it will not change. The only way to change the state is to create a new one. So everytime something changes, we have a new state. That makes is an excellent cache key!

Code Snippets

function memoizeFirst(fn) {
    const cache = new WeakMap();
    return function(arg) {
        if (!cache.has(arg)) {
            cache.set(arg, fn(arg));
        }
        return cache.get(arg);
    };
}
const getParentObjectIndex = memoizeFirst(state => state.objectSource && state.objectSource.
    where(objectItem => objectItem.parentObject).
    groupBy(objectItem => objectItem.parentObject).
    reduce(function(map, group) {
        map[group.key] = group.
        orderBy(item => item.position).
        toArray();
        return map;
    }, {})
);

Context

StackExchange Code Review Q#21192, answer score: 4

Revisions (0)

No revisions yet.