Reputation: 6692
I need to merge two objects in a code path that is going to be heavily used. The code works, but I am concerned it is not optimized enough for speed and I am looking for any suggestions to improve/replace what I have come up with. I originally started working off an example at the end of this issue: How can I merge properties of two JavaScript objects dynamically?. That solution works well for simple objects. However, my needs have a twist to it which is where the performance concerns come in. I need to be able to support arrays such that
I do not need functions/method cloning and I don't care about hasOwnProperty since the objects go back to JSON strings after merging.
Any suggestions to help me pull every last once of performance from this would be greatly appreciated.
var utils = require("util");
function mergeObjs(def, obj) {
if (typeof obj == 'undefined') {
return def;
} else if (typeof def == 'undefined') {
return obj;
}
for (var i in obj) {
// if its an object
if (obj[i] != null && obj[i].constructor == Object)
{
def[i] = mergeObjs(def[i], obj[i]);
}
// if its an array, simple values need to be joined. Object values need to be remerged.
else if(obj[i] != null && utils.isArray(obj[i]) && obj[i].length > 0)
{
// test to see if the first element is an object or not so we know the type of array we're dealing with.
if(obj[i][0].constructor == Object)
{
var newobjs = [];
// create an index of all the existing object IDs for quick access. There is no way to know how many items will be in the arrays.
var objids = {}
for(var x= 0, l= def[i].length ; x < l; x++ )
{
objids[def[i][x].id] = x;
}
// now walk through the objects in the new array
// if the ID exists, then merge the objects.
// if the ID does not exist, push to the end of the def array
for(var x= 0, l= obj[i].length; x < l; x++)
{
var newobj = obj[i][x];
if(objids[newobj.id] !== undefined)
{
def[i][x] = mergeObjs(def[i][x],newobj);
}
else {
newobjs.push(newobj);
}
}
for(var x= 0, l = newobjs.length; x<l; x++) {
def[i].push(newobjs[x]);
}
}
else {
for(var x=0; x < obj[i].length; x++)
{
var idxObj = obj[i][x];
if(def[i].indexOf(idxObj) === -1) {
def[i].push(idxObj);
}
}
}
}
else
{
def[i] = obj[i];
}
}
return def;}
The object samples to merge:
var obj1 = {
"name" : "myname",
"status" : 0,
"profile": { "sex":"m", "isactive" : true},
"strarr":["one", "three"],
"objarray": [
{
"id": 1,
"email": "[email protected]",
"isactive":true
},
{
"id": 2,
"email": "[email protected]",
"isactive":false
}
]
};
var obj2 = {
"name" : "myname",
"status" : 1,
"newfield": 1,
"profile": { "isactive" : false, "city": "new York"},
"strarr":["two"],
"objarray": [
{
"id": 1,
"isactive":false
},
{
"id": 2,
"email": "[email protected]"
},
{
"id": 3,
"email": "[email protected]",
"isactive" : true
}
]
};
Once merged, this console.log(mergeObjs(obj1, obj2)) should produce this:
{ name: 'myname',
status: 1,
profile: { sex: 'm', isactive: false, city: 'new York' },
strarr: [ 'one', 'three', 'two' ],
objarray:
[ { id: 1, email: '[email protected]', isactive: false },
{ id: 2, email: '[email protected]', isactive: false },
{ id: 3, email: '[email protected]', isactive: true } ],
newfield: 1 }
Upvotes: 3
Views: 3034
Reputation: 12722
I'd check out: https://github.com/bestiejs/lodash
_.merge
is not on the list of 'optimized' functions, but this is a battle tested, battle hardened. He also has a performance suite, could ask how you might contribute to the perf suite to get some visibility into the merge
implementation.
https://github.com/bestiejs/lodash/blob/master/lodash.js#L1677-1738
Edit: As an aside, I wouldn't prematurely optimize. I would see if this is actually a problem in your use case and then move on to actual data. I would look at something like: https://github.com/felixge/faster-than-c
Basic tenets:
He's got tips on each of those.
Upvotes: 3
Reputation: 20871
If you don't use Lo-Dash, and just want a tool to merge two objects including their arrays, use deepmerge: https://github.com/nrf110/deepmerge
npm install deepmerge
Upvotes: 1