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

Object map() / transmute() method

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

Problem

I'm somewhat curious on peoples opinion about such a method. I Actually didn't find anything similar in librarys I use on regular bases so far.

This is my implementation:

Object.map = function _map( obj, transform ) {
    if( typeof obj === 'object' && typeof transform === 'function' ) {
        Object.keys( obj ).forEach(function _forEach( key ) {
            (function _mapping( oldkey, transmuted ) {
                if( transmuted && transmuted.length ) {
                    obj[ transmuted[ 0 ] || oldkey ] = transmuted[ 1 ];

                    if( transmuted[ 0 ] && oldkey !== transmuted[ 0 ] ) {
                        delete obj[ oldkey ];
                    }
                }
            }( key, transform.apply( obj, [ key, obj[ key ]] ) ));
        });
    }
};


I normally put it on the Object object and not the prototype. However, usage is like this

var foo = {
    someProp: 5,
    bar: 10,
    moar: 20
};

Object.map( foo, function(key, value) {
    return [ key.toUpperCase(), value*2 ];
});


result:

Object { SOMEPROP=10, BAR=20, MOAR=40}


I most often use it to translate CSS properties (to vendor prefixes). But I don't see people use an approach like this often in ECMAscript. Any thoughts?

Solution

First comment, there is no need for the closure inside _forEach which makes the code unnecessarily difficult to read. More importantly I would argue that the function would be much more useful if did not transform the original object and instead returned a new object.

Object.map = function (obj, mapping) {
    var mapped = {};

    if (typeof obj !== 'object') {
        return mapped;
    }

    if (typeof mapping !== 'function') {
        // We could just return obj but that wouldn't be
        // consistent with the rest of the interface which always returns
        // a new object.
        mapping = function (key, val) {
            return [ key, val ];
        };
    }

    Object.keys( obj ).forEach(function (key) {
        var transmuted = mapping.apply(obj, [ key, value ]);

        if (transmuted && transmuted.length) {
            mapped[ transmuted[0] || key ] = kv[ 1 ];
        }
    });

    return mapped;
};


This is not only less dangerous for widely available object but it also makes the function more flexible by allowing it to be chained or used within an expression:

Object.map(oldCss, function (key, value) {
    // ...
}).doSomethingElse();


At the very least I would have your original function return the passed in object to allow for chaining or use within an expression.

Code Snippets

Object.map = function (obj, mapping) {
    var mapped = {};

    if (typeof obj !== 'object') {
        return mapped;
    }

    if (typeof mapping !== 'function') {
        // We could just return obj but that wouldn't be
        // consistent with the rest of the interface which always returns
        // a new object.
        mapping = function (key, val) {
            return [ key, val ];
        };
    }

    Object.keys( obj ).forEach(function (key) {
        var transmuted = mapping.apply(obj, [ key, value ]);

        if (transmuted && transmuted.length) {
            mapped[ transmuted[0] || key ] = kv[ 1 ];
        }
    });

    return mapped;
};
Object.map(oldCss, function (key, value) {
    // ...
}).doSomethingElse();

Context

StackExchange Code Review Q#6189, answer score: 4

Revisions (0)

No revisions yet.