I have:
var obj = {'a': {some object}, 'b': {some other object}, 'c':{some other object},...}
I want to write a function that will overwrite any single key in my original object.
myFunction(obj, {'a': {new object}});
console.log(obj);
//{'a': {new object}, 'b': {some other object}, 'c':{some other object},...}
I am using lodash. I obviously know that I can do _.keys then get the only item in the array and then assign it manually but I wonder if there is a less cumbersome way.
The _.extend function, available as Object.assign in ES6-compatible Javascript, does what you want.
_.extend({ a: 1, b: 2 }, { a: 10 })
// { a: 10, b: 2 }
The function is more flexible than simple assignment: you can add or replace any number of keys, shallow-merging the objects passed as parameters.
No need of Lodash/Underscore, this can be done in JavaScript easily.
obj[key] = newObject;
var obj = {
one: {
1: 'ONE'
},
two: {
2: 'TWO'
},
three: {
3: 'THREE'
}
};
obj['two'] = {
22: 'Two Two'
};
console.log(obj);
UPDATE:
You can use Object.assign()
Object.assign(obj, {
two: {
22: 'Two Two'
}
});
Related
I have two Object like this and want to merge them:
const obj1 = {
1: { foo: 1 },
2: { bar: 2, fooBar: 3 },
3: { fooBar: 3 },
};
const obj2 = {
1: { foo: 1, bar: 2 },
2: { bar: 2 },
};
const merged = someMergingMethod(obj1, obj2);
merged === {
1: { foo: 1, bar: 2 },
2: { bar: 2, fooBar: 3 },
3: { fooBar: 3 },
};
I mean, I want to not only merge the objects, but also merge their object values' properties too if the key is duplicated.
Because just merged = { ...obj1, ...obj2 }; overwrites the properties with obj2's.
What is the easiest way to do this?
I can use ES2017 and other libraries like lodash.
You can use spread operator.
Update :
if obj2 has some properties that obj1 does not have?
Initially i wrote this answer assuming the keys are indexed like 0,1 and so on but as you mentioned in comment this is not the case than you can build a array of keys and than iterate over it as
as very concisely added in comment by #Nick [...Object.keys(obj1), ...Object.keys(obj2)]
let obj1 = {1: { foo: 1 },2: { bar: 2, fooBar: 3 },3: { fooBar: 3 },};
let obj2 = {1: { foo: 1, bar: 2 },2: { bar: 2 },};
let keys = [...new Set([...Object.keys(obj1),...Object.keys(obj2)])]
let op = {}
let merged = keys.forEach(key=>{
op[key] = {
...obj1[key],
...obj2[key]
}
})
console.log(op)
Since you mentioned you can use lodash you can use merge like so:
_.merge(obj1, obj2)
to get your desired result.
See working example below:
const a = {
1: { foo: 1 },
2: { bar: 2, fooBar: 3 },
3: { fooBar: 3 },
},
b = {
1: { foo: 1, bar: 2 },
2: { bar: 2 },
4: {foo: 1}
},
res = _.merge(a, b);
console.log(res);
<script src="https://cdn.jsdelivr.net/lodash/4.16.4/lodash.min.js"></script>
I have exactly what you want.
This function will traverse through each nested object and combine it with the other. I've only tested it with 5 nested levels down the tree but, theoretically, it should work for any number of nested objects as it is a recursive function.
//this function is similar to object.assign but,
//leaves the keys which are common among both bojects untouched
function merge(object1, object2)
{
function combine(p, q)
{
for(i in q)
if(!p.hasOwnProperty(i))
p[i]= q[i];
return p;
}
obj1= Object.assign(combine(obj1, obj2), obj1);//for the first level
obj1= Object.assign(traverse(obj1, obj2), obj1);//for subsequent levels down theobjectt tree
//this function traverses each nested boject and combines it with the other object
function traverse(a, b)
{
if(typeof(a) === "object" && typeof(b) === "object")
for(i in b)
if(typeof(a[i]) === "object" && typeof(b[i]) === "object")
a[i]= Object.assign(traverse(a[i], b[i]), a[i]);
else
Object.assign(combine(a, b), a);
return a;
}
return obj1;
}
console.log(merge(obj1, obj2));
Here is a working example of a much more complex object merging
var obj1 = {
1: { foo: 1 },
2: { bar: 2, fooBar: 3 },
3: { fooBar: 3, boor:{foob: 1, foof: 8} },
4: {continent: {
asia: {country: {india: {capital: "delhi"}, china: {capital: "beiging"}}},
europe:{country:{germany: {capital: "berlin"},france: {capital: "paris"}}}
},
vegtables: {cucumber: 2, carrot: 3, radish: 7}
}
};
var obj2 = {
1: { foo: 1, bar: 2 },
2: { bar: 2 },
3: {fooBar: 3, boor:{foob: 1, boof: 6}, boob: 9 },
4: {continent: {
northamerica: {country: {mexico: {capital: "mexico city"}, canada: {capital: "ottawa"}},},
asia: {country: {Afghanistan : {capital: "Kabul"}}}
}
},
5: {barf: 42}
};
//this function is similar to object.assign but,
//leaves the keys which are common among both bojects untouched
function merge(object1, object2)
{
function combine(p, q)
{
for(i in q)
if(!p.hasOwnProperty(i))
p[i]= q[i];
return p;
}
obj1= Object.assign(combine(obj1, obj2), obj1);//for the first level
obj1= Object.assign(traverse(obj1, obj2), obj1);//for subsequent levels down the object tree
//this function traverses each nested boject and combines it with the other object
function traverse(a, b)
{
if(typeof(a) === "object" && typeof(b) === "object")
for(i in b)
if(typeof(a[i]) === "object" && typeof(b[i]) === "object")
a[i]= Object.assign(traverse(a[i], b[i]), a[i]);
else
Object.assign(combine(a, b), a);
return a;
}
return obj1;
}
console.log(merge(obj1, obj2));
you can use Object.assign and and assign object properties to empty object.
var a = {books: 2};
var b = {notebooks: 1};
var c = Object.assign( {}, a, b );
console.log(c);
or
You could use merge method from Lodash library.
can check here :
https://www.npmjs.com/package/lodash
Are you looking like this?
we can use this way to merge two objects.
const person = { name: 'David Walsh', gender: 'Male' };
const attributes = { handsomeness: 'Extreme', hair: 'Brown', eyes: 'Blue' };
const summary = {...person, ...attributes};
/*
Object {
"eyes": "Blue",
"gender": "Male",
"hair": "Brown",
"handsomeness": "Extreme",
"name": "David Walsh",
}
*/
This can be easily accomplished with a combination of the neat javascript spread syntax, Array and Object prototype functions, and destructuring patterns.
[obj1,obj2].flatMap(Object.entries).reduce((o,[k,v])=>({...o,[k]:{...o[k],...v}}),{})
As simple as this!
For a very detailed explanation of how this works, refer to this extended answer to a similar question.
Consider the following two objects:
const source = {
foo: 'value',
bar: 'value',
baz: 'value'
};
const pattern = {
foo: '',
bar: ''
};
_.fn(source, pattern); // { foo: 'value', bar: 'value' }
In this example 'baz' property is deleted because it doesn't exist in the pattern.
_.pick can help
_.pick(source,Object.keys(pattern))
If you want to mutate the original source object for inline key deletion instead of returning a new one, you can do:
_.difference(_.keys(source), _.keys(pattern)).forEach(k => delete source[k])
Or just plain JS:
Object.keys(source)
.filter(k => Object.keys(pattern).includes(k))
.forEach(k => delete source[k])
I generally design for immutability, but this approach might be useful if you want to avoid the overhead of allocating a new object, or you have a lot of primitives that would need copying over by value to a fresh object.
What you can do as well, is look for intersection ofthose two objects:
var a = { 'a': 1, 'b': 2, 'c': 3 };
var b = { 'c': 3, 'd': 4, 'e': 5 };
_.intersection(_.keys(a), _.keys(b)); // ['c']
I am working with JavaScript, could you help me please
Here is my problem.
I have this object:
var MyObj= [{ a: 0, b: "Zero", c: "x", d: "!" }, { a: 1, b: "One", c: "y", d: "#" }]
I want to change the element of selected object ("a" --> "id") to become like this:
var NewObj= [{ id: 0, b: "Zero", c: "x", d: "!" }, { id: 1, b: "One", c: "y", d: "#" }]
I tried to use $.map() method like this
NewObj= $.map(MyObj, function (obj) {
return { id: obj.a, b: obj.b, c: obj.c, d:obj.d };
});
Is there any better way to do this since I only change one element of object?
No need for ES6 / Object.assign, no need for jQuery:
Working Fiddle: https://jsbin.com/gosaqid/edit?js,console
function makeObj(obj){
return obj.map(function(el, i) {
el.id = i;
delete el.a;
return el;
});
}
Not unless you have a clone/copy/extend function available. One is coming up in new JavaScript, and jQuery has one, and it's not very hard writing your own. But it still isn't a walk in the park - you can't just rename a property, you need to copy and delete:
NewObj = MyObj.map(function(obj) {
var newobj = Object.assign({}, obj, {id: obj.a});
delete newobj.a;
return newobj;
});
In your example MyObj is an array of objects.
var object = {}
var array = []
var arrayOfObjects = [{}, {}, {}]
In your desired result, you have changed one of the keys of every object in the array.
Using map is a perfectly adequate way of doing this, in fact JavaScript's array has a built in map method.
var newArrayOfObjects = arrayOfObjects.map(function (obj) {
return {
id: obj.a,
b: obj.b,
c: obj.c
}
})
If you have a ton of keys this can get a little verbose so you can use $.extend, but chances are you're writing code for modern browsers so the whole thing can be written as such:
var newArrayOfObjects = arrayOfObjects.map(obj =>
Object.assign({}, obj, { id: obj.a })
)
update: as #Amadan suggests, you can also delete the old key if you need
I have an object in my .js file (node)
var z = [
{'a': 'uno', 'b': 'dos'},
{'a': 'uno', 'b': 'dos'},
{'a': 'uno', 'b': 'dos'},
{'a': 'uno', 'b': 'dos'}
];
I would like to omit each 'a' from z object.
I'm trying with something like this, but is not working.
var y = _.forEach(z, function(n){
//console.log(_.omit(n, 'a'));
return _.omit(n, 'a');
});
console.log(y);
I tried without return, and few ways more, but didn't get it.
My jsfiddle link: http://jsfiddle.net/baumannzone/jzs6n78m/
Any help? Cheers!
Create a new array of objects, by omitting a from each of them
console.log(_.map(z, function (obj) {
return _.omit(obj, 'a');
}));
// [ { b: 'dos' }, { b: 'dos' }, { b: 'dos' }, { b: 'dos' } ]
As it is, you are omitting and creating a new object but that object is ignored by _.each. Now, we use _.map, which will gather all the values returned from the function and form a new array.
If you prefer a one-liner, create a partial function and leave only the object to be used as _, like this
console.log(_.map(z, _.partial(_.omit, _, 'a')));
// [ { b: 'dos' }, { b: 'dos' }, { b: 'dos' }, { b: 'dos' } ]
var y = _.map(z, function(n) {
return _.omit(n, 'a');
});
This will create a new array from the old one, mapping the objects in z to new objects that omit the 'a' attribute.
An alternative is to use chaining, so:
var y = _(z).map(function(n){return n.omit('a');}).value();
B
I want to add multiple attributes to an existing object with existing attributes. Is there a more concise way than one line per new attribute?
myObject.name = 'don';
myObject.gender = 'male';
Everything on MDN shows how to do new objects with bracket notation, but not existing objects: https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Working_with_Objects
In ES6/ ES2015 you can use the Object.assign method
let obj = {key1: true};
console.log('old obj: ', obj);
let newObj = {key2: false, key3: false};
Object.assign(obj, newObj);
console.log('modified obj: ', obj);
I'm not sure if that's helpful, but there is a trick using JS ES6 spread syntax:
let obj = {a: 1, b: 2};
obj = {...obj, b: 3, c: 4};
console.log(obj); // {a: 1, b: 3, c: 4}
You can try to use this somehow... In general, that's a single liner to add or override object properties using js destructuring method.
Edit:
Notice that the placement of ...obj in the new object is cruicial, as placing it first would allow overriding it with the following params (b: 3, c: 4 in my example), and placing it last will give priority to the members that are already in the object.
From How can I merge properties of two JavaScript objects dynamically?
var obj2 = {name: 'don', gender: 'male'};
for (var attrname in myobject) { myobject[attrname] = obj2[attrname]; }
EDIT
To be a bit clearer about how you could extend Object to use this function:
//Extend the protype so you can make calls on the instance
Object.prototype.merge = function(obj2) {
for (var attrname in obj2) {
this[attrname] = obj2[attrname];
}
//Returning this is optional and certainly up to your implementation.
//It allows for nice method chaining.
return this;
};
//Append to the object constructor function so you can only make static calls
Object.merge2 = function(obj1, obj2) {
for (var attrname in obj2) {
obj1[attrname] = obj2[attrname];
}
//Returning obj1 is optional and certainly up to your implementation
return obj1;
};
Usage:
var myObject1 = { One: "One" };
myObject1.merge({ Two: "Two" }).merge({ Three: "Three" });
//myObject1 is { One: "One", Two: "Two", Three: "Three", merge: function }
var myObject2 = Object.merge2({ One: "One" }, { Two: "Two" });
Object.merge2(myObject2, { Three: "Three" });
//myObject2 is { One: "One", Two: "Two", Three: "Three" }
Note: You certainly could implement a flexible merge conflict strategy depending on your needs.
Use jQuery library
jQuery.extend(myObject, { name : 'don', gender : 'male' });
Sometimes I do it like this:
var props = {
name : 'don',
gender : 'male',
age : 12,
other : false
};
for(var p in props) myObject[p] = props[p];
In ECMAscript 5 you can make us of defineProperties:
Object.defineProperties(myobject, {
name: {
value: 'don'
},
gender: {
value: 'male'
}
});