I have an object:
myObject = { \'a\': 1, \'b\': 2, \'c\': 3 }
I am looking for a native method, similar to Array.prototype.map
Hey wrote a little mapper function that might help.
function propertyMapper(object, src){
for (var property in object) {
for (var sourceProp in src) {
if(property === sourceProp){
if(Object.prototype.toString.call( property ) === '[object Array]'){
propertyMapper(object[property], src[sourceProp]);
}else{
object[property] = src[sourceProp];
}
}
}
}
}
Minimal version (es6):
Object.entries(obj).reduce((a, [k, v]) => (a[k] = v * v, a), {})
For maximum performance.
If your object doesn't change often but needs to be iterated on often I suggest using a native Map as a cache.
// example object
var obj = {a: 1, b: 2, c: 'something'};
// caching map
var objMap = new Map(Object.entries(obj));
// fast iteration on Map object
objMap.forEach((item, key) => {
// do something with an item
console.log(key, item);
});
Object.entries already works in Chrome, Edge, Firefox and beta Opera so it's a future-proof feature. It's from ES7 so polyfill it https://github.com/es-shims/Object.entries for IE where it doesn't work.
I came upon this as a first-item in a Google search trying to learn to do this, and thought I would share for other folsk finding this recently the solution I found, which uses the npm package immutable.
I think its interesting to share because immutable uses the OP's EXACT situation in their own documentation - the following is not my own code but pulled from the current immutable-js documentation:
const { Seq } = require('immutable')
const myObject = { a: 1, b: 2, c: 3 }
Seq(myObject).map(x => x * x).toObject();
// { a: 1, b: 4, c: 9 }
Not that Seq has other properties ("Seq describes a lazy operation, allowing them to efficiently chain use of all the higher-order collection methods (such as map and filter) by not creating intermediate collections") and that some other immutable-js data structures might also do the job quite efficiently.
Anyone using this method will of course have to npm install immutable
and might want to read the docs:
https://facebook.github.io/immutable-js/
How about a one liner with immediate variable assignment in plain JS (ES6 / ES2015) ?
Making use of spread operator and computed key name syntax:
let newObj = Object.assign({}, ...Object.keys(obj).map(k => ({[k]: obj[k] * obj[k]})));
jsbin
Another version using reduce:
let newObj = Object.keys(obj).reduce((p, c) => ({...p, [c]: obj[c] * obj[c]}), {});
jsbin
First example as a function:
const oMap = (o, f) => Object.assign({}, ...Object.keys(o).map(k => ({ [k]: f(o[k]) })));
// To square each value you can call it like this:
let mappedObj = oMap(myObj, (x) => x * x);
jsbin
If you want to map a nested object recursively in a functional style, it can be done like this:
const sqrObjRecursive = obj =>
Object.keys(obj).reduce(
(newObj, key) =>
obj[key] && typeof obj[key] === "object"
? { ...newObj, [key]: sqrObjRecursive(obj[key]) } // recurse.
: { ...newObj, [key]: obj[key] * obj[key] }, // square val.
{}
);
jsbin
Or more imperatively, like this:
const sqrObjRecursive = obj => {
Object.keys(obj).forEach(key => {
if (typeof obj[key] === "object") obj[key] = sqrObjRecursive(obj[key]);
else obj[key] = obj[key] * obj[key];
});
return obj;
};
jsbin
Since ES7 / ES2016 you can use Object.entries() instead of Object.keys()
e.g. like this:
let newObj = Object.assign({}, ...Object.entries(obj).map(([k, v]) => ({[k]: v * v})));
ES2019 introduced Object.fromEntries(), which simplifies this even more:
let newObj = Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, v * v]));
In some rare situation you may need to map a class-like object which holds properties of an inherited object on its prototype-chain. In such cases Object.keys()
won't work, because Object.keys()
does not enumerate inherited properties. If you need to map inherited properties, you should use for (key in myObj) {...}
.
Here is an example of an object which inherits the properties of another object and how Object.keys()
doesn't work in such scenario.
const obj1 = { 'a': 1, 'b': 2, 'c': 3}
const obj2 = Object.create(obj1); // One of multiple ways to inherit an object in JS.
// Here you see how the properties of obj1 sit on the 'prototype' of obj2
console.log(obj2) // Prints: obj2.__proto__ = { 'a': 1, 'b': 2, 'c': 3}
console.log(Object.keys(obj2)); // Prints: an empty Array.
for (key in obj2) {
console.log(key); // Prints: 'a', 'b', 'c'
}
jsbin
However, please do me a favor and avoid inheritance. :-)
I handle only strings to reduce exemptions:
Object.keys(params).map(k => typeof params[k] == "string" ? params[k] = params[k].trim() : null);