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?
1 Answer 1
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.
jQuery.each()does exactly that. \$\endgroup\$