Reputation: 63728
I want to merge two objects into a new object, with one object overwriting properties if both have them.
This is very easy to do with ES6 spreads, but in this particular case I would like to use a method that still defines what keys can be set. Basically create a "white list" of properties that are allowed on my final object. (With spreads, any property would be merged into the new object).
Is there a method that uses ES6+ to do this?
Two objects:
var o1 = {
a: 'foo',
b: 'bar',
c: 'baz'
}
var o2 = {
a: 'pop',
bad_property: 'dont copy me'
}
var oMerged = {
a: 'pop', // I came from obj_2
b: 'bar',
c: 'baz'
}
Merge methods:
// Method 1: Use spreads, problem is this hides the keys.
var oMerged = {
...o1,
...o2
};
// Method 2: Shows each key, but requires a ternary to check if obj_2 has the key.
var oMerged = {
a: (o2.a !== undefined) ? o2.a : o1.a,
b: (o2.b !== undefined) ? o2.b : o1.b,
c: (o2.c !== undefined) ? o2.c : o1.c
}
// Method 3: Define what keys can be merged, but use a more concise syntax / possibly an ES6+ feature.
???
Edit: Explicitly said that the object should have a white list of acceptable properties. There are good answers but they require black lists of unacceptable properties. The reason for the 'white list' is it shows other developers the shape of the final object.
Upvotes: 0
Views: 253
Reputation: 4025
Here you go, you can use the factory()
function to create different merge functions, each with its own set of allowed words and then call those functions to merge an arbitrary number of objects.
const obj1 = {
a: 'foo',
b: 'bar',
c: 'baz'
}
const obj2 = {
a: 'pop',
bad_property: 'dont copy me'
}
const obj3 = {
another_one: 'test',
another_bad_property: 'dont copy this either'
}
const factory = allowed => {
return (...args) => {
const temp = {}
args.forEach(obj => {
Object.keys(obj).forEach(key => {
if (allowed.indexOf(key) !== -1) {
temp[key] = obj[key]
}
})
})
return temp
}
}
const mergeWith4AllowedKeys = factory(['a', 'b', 'c', 'another_one'])
const merged = mergeWith4AllowedKeys(obj1, obj2, obj3)
console.log(merged)
const mergeWith3AllowedKeys = factory(['a', 'b', 'c'])
const secondBatch = mergeWith3AllowedKeys(obj1, obj2) // only 2
console.log(secondBatch)
Upvotes: 1
Reputation: 63728
This is the shortest method I've come up with that will let you
not require long ternaries for each property
// Step 1. merge all properties into a new object.
var oMerged = {...o1, ...o2};
// Step 2. Explicitly use keys to assign
var oFinal = {
a: oM.a,
b: oM.b,
c: oM.c
};
Upvotes: 0
Reputation: 2816
This is ES2017 Spread and Rest implementation, it is supported for example in typescript ^2.1
With o1
and o2
as you have it, you can write:
let merged = { ...o1, ...o2 };
// and then use Object rest as the dual of object spreads, to pick up the wanted properties
let { bad_property, ...oMerged } = merged;
Upvotes: 0
Reputation: 14778
You could use an omit
function (such as this one provided by lodash) to create a clone of an object without certain keys. Then you could merge that object:
function omit(object, blacklist) {
return Object.keys(object).reduce((result, key) => {
if(!blacklist.includes(key)) {
result[key] = object[key];
}
return result;
}, {});
}
var o1 = {
a: 'foo',
b: 'bar',
c: 'baz'
}
var o2 = {
a: 'pop',
bad_property: 'dont copy me'
}
var blacklist = ['bad_property'];
var merged = {
...omit(o1, blacklist),
...omit(o2, blacklist)
};
console.log(merged);
Upvotes: 0
Reputation: 1641
Try...
function (Obj1,Obj2) {
['can','set','these'].forEach(key => Obj1[key] && ( Obj2[key] = Obj1[key] ) )
}
Upvotes: 0