161

I am looking for the best way to "add" multiple JavaScript objects (associative arrays).

For example, given:

a = { "one" : 1, "two" : 2 };
b = { "three" : 3 };
c = { "four" : 4, "five" : 5 };

what is the best way to compute:

{ "one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }
2
  • 3
    A semantic note: despite the [] syntax, they aren't arrays at all. Order is not really guaranteed. Commented Mar 16, 2010 at 12:44
  • 2
    Iteration order is not guaranteed per ecma standards. But it is the way it is implemented in most browsers. (From John Resig) This behavior is explicitly left undefined by the ECMAScript specification. In ECMA-262, section 12.6.4: The mechanics of enumerating the properties ... is implementation dependent. However, specification is quite different from implementation. All modern implementations of ECMAScript iterate through object properties in the order in which they were defined. Because of this the Chrome team has deemed this to be a bug and will be fixing it. Commented Mar 16, 2010 at 13:44

14 Answers 14

229

ECMAscript 6 introduced Object.assign() to achieve this natively in Javascript.

The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object. It will return the target object.

MDN documentation on Object.assign()

var o1 = { a: 1 };
var o2 = { b: 2 };
var o3 = { c: 3 };

var obj = Object.assign({}, o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }

Object.assign is supported in many modern browsers but not yet all of them. Use a transpiler like Babel and Traceur to generate backwards-compatible ES5 JavaScript.

Sign up to request clarification or add additional context in comments.

5 Comments

This is one of the best I could say. Since E6 is now mostly used, Object.assign is the best answer.
If you don't know how many objects need to be merge, bevause they are in an array you can merge them as follows: Object.assign.apply({}, [{a: 1}, {b: 2}, ....])
An alternative to using Object.assign.apply to merge an array of objects, is to instead use the spread operator: Object.assign( ...objects )
after 4 hours, this answer solved my problem in Angular 7. Thanks for the simplicity and accurateness of answer.
What an answer!
75

ECMAScript 6 has spread syntax. And now you can do this:

const obj1 = { 1: 11, 2: 22 };
const obj2 = { 3: 33, 4: 44 };
const obj3 = { ...obj1, ...obj2 };

console.log(obj3); // {1: 11, 2: 22, 3: 33, 4: 44}

3 Comments

This should be the accepted answer, because it is the most modern one. Object.assign is old now and not as readable as this one.
yep, but what if you have an array of objects. with assign you can just do Object.assign({}, ...objcs) or Object.assign.apply({}, objcs)
There are known performance pitfalls with large datasets when using the spread ... operator. Developers should know how Object.assign and ... work and use accordingly.
35

This should do it:

function collect() {
  var ret = {};
  var len = arguments.length;
  for (var i = 0; i < len; i++) {
    for (p in arguments[i]) {
      if (arguments[i].hasOwnProperty(p)) {
        ret[p] = arguments[i][p];
      }
    }
  }
  return ret;
}

let a = { "one" : 1, "two" : 2 };
let b = { "three" : 3 };
let c = { "four" : 4, "five" : 5 };

let d = collect(a, b, c);
console.log(d);

Output:

{
  "one": 1,
  "two": 2,
  "three": 3,
  "four": 4,
  "five": 5
}

8 Comments

Doesn't length lookup the size of the array at each invocation? I'm so used to writing for (var i = 0, len = array.length; i < len; ++i) that I can't remember off the top of my head why I started doing it.
Yes, that's correct. It is better performance to cache the length once. However, because the size of the arguments "array" is not likely to ever be very large, it won't really matter in this case.
No, except slightly on IE6. Accessing the length property costs the same as accessing the len variable.
@Juan I believe you are incorrect, and I did some tests to make up my mind. Caching the length is an easy myth of optimization that's been obsolete for many years, and it makes the code (slightly) less readable. Actually, caching the length sometimes slows down the browser (Safari).
Wouldn't it be better to write 'for (var p in...' instead of 'for (p in...' ?
|
34

You could use jquery's $.extend like this:

let a = { "one" : 1, "two" : 2 },
    b = { "three" : 3 },
    c = { "four" : 4, "five" : 5 };

let d = $.extend({}, a, b, c)

console.log(d)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

3 Comments

+1 Even if you don't use jQuery's method, you could use their code to help construct your own (perhaps, more specific) implementation.
@Randal: There are many perfectly good reasons for not using jQuery.
Edit: d = $.extend({},a,b,c);
12

Underscore has few methods to do this;

1. _.extend(destination, *sources)

Copy all of the properties in the source objects over to the destination object, and return the destination object.

_.extend(a, _.extend(b, c));
=> {"one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }

Or

_.extend(a, b);
=> {"one" : 1, "two" : 2, "three" : 3}
_.extend(a, c);
=> {"one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }

2. _.defaults(object, *defaults)

Fill in undefined properties in object with values from the defaults objects, and return the object.

_.defaults(a, _.defaults(b, c));
=> {"one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }

Or

_.defaults(a, b);
=> {"one" : 1, "two" : 2, "three" : 3}
_.defaults(a, c);
=> {"one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }

Comments

9

Shallow-cloning (excluding prototype) or merging of objects is now possible using a shorter syntax than Object.assign().

Spread syntax for object literals was introduced in ECMAScript 2018):

const a = { "one": 1, "two": 2 };
const b = { "three": 3 };
const c = { "four": 4, "five": 5 };

const result = {...a, ...b, ...c};
// Object { "one": 1, "two": 2 , "three": 3, "four": 4, "five": 5 }

Spread (...) operator is supported in many modern browsers but not all of them.

So, it is recommend to use a transpiler like Babel to convert ECMAScript 2015+ code into a backwards compatible version of JavaScript in current and older browsers or environments.

This is the equivalent code Babel will generate for you:

"use strict";

var _extends = Object.assign || function(target) {
  for (var i = 1; i < arguments.length; i++) {
    var source = arguments[i];
    for (var key in source) {
      if (Object.prototype.hasOwnProperty.call(source, key)) {
        target[key] = source[key];
      }
    }
  }
  return target;
};

var a = { "one": 1, "two": 2 };
var b = { "three": 3 };
var c = { "four": 4, "five": 5 };

var result = _extends({}, a, b, c);
// Object { "one": 1, "two": 2 , "three": 3, "four": 4, "five": 5 }

1 Comment

This is a much more robust answer than the accepted answer. Thanks!
6

To merge a dynamic number of objects, we can use Object.assign with spread syntax.

const mergeObjs = (...objs) => Object.assign({}, ...objs);

The above function accepts any number of objects, merging all of their properties into a new object with properties from later objects overwriting those from previous objects.

Demo:

const mergeObjs = (...objs) => Object.assign({}, ...objs);
const a = {prop: 1, prop2: '2'},
      b = {prop3: 3, prop4: [1,2,3,4]}
      c = {prop5: 5},
      d = {prop6: true, prop7: -1},
      e = {prop1: 2};
const abcd = mergeObjs(a,b,c,d);
console.log("Merged a,b,c,d:", abcd);
const abd = mergeObjs(a,b,d);
console.log("Merged a,b,d:", abd);
const ae = mergeObjs(a,e);//prop1 from e will overwrite prop1 from a
console.log("Merged a,e:", ae);

To merge an array of objects, a similar method may be applied.

const mergeArrayOfObjs = arr => Object.assign({}, ...arr);

Demo:

const mergeArrayOfObjs = arr => Object.assign({}, ...arr);
const arr = [
  {a: 1, b: 2},
  {c:1, d:3},
  {abcd: [1,2,3,4], d: 4}
];
const merged = mergeArrayOfObjs(arr);
console.log(merged);

Comments

4

Why should the function be restricted to 3 arguments? Also, check for hasOwnProperty.

function Collect() {
    var o={};
    for(var i=0;i<arguments.length;i++) {
      var arg=arguments[i];
      if(typeof arg != "object") continue;
      for(var p in arg) {
        if(arg.hasOwnProperty(p)) o[p] = arg[p];
      }
    }
    return o;
}

Comments

4

It's easy using ES7 spread operator for an object, in your browser console put

({ name: "Alex", ...(true  ? { age: 19 } : { })}) // {name: "Alex", age: 19}
({ name: "Alex", ...(false ? { age: 19 } : { })}) // {name: "Alex",        }

2 Comments

Nice. This question is more than 10 years old, glad that such simple operation is easy now. It wasn't that easy before if you look at the other people's answers.
that's why I left my own answer :)
3
function Collect(a, b, c) {
    for (property in b)
        a[property] = b[property];

    for (property in c)
        a[property] = c[property];

    return a;
}

Notice: Existing properties in previous objects will be overwritten.

1 Comment

This has the side-effect that a === d at the end. That might be ok and it might not.
3

ES6 ++

The question is adding various different objects into one.

let obj = {};
const obj1 = { foo: 'bar' };
const obj2 = { bar: 'foo' };
Object.assign(obj, obj1, obj2);
//output => {foo: 'bar', bar: 'foo'};

lets say you have one object with multiple keys that are objects:

let obj = {
  foo: { bar: 'foo' },
  bar: { foo: 'bar' }
}

this was the solution I found (still have to foreach :/)

let objAll = {};

Object.values(obj).forEach(o => {
  objAll = {...objAll, ...o};
});

By doing this we can dynamically add ALL object keys into one.

// Output => { bar: 'foo', foo: 'bar' }

Comments

1

Probably, the fastest, efficient and more generic way is this (you can merge any number of objects and even copy to the first one ->assign):

function object_merge(){
    for (var i=1; i<arguments.length; i++)
       for (var a in arguments[i])
         arguments[0][a] = arguments[i][a];
   return arguments[0];
}

It also allows you to modify the first object as it passed by reference. If you don't want this but want to have a completely new object containing all properties, then you can pass {} as the first argument.

var object1={a:1,b:2};
var object2={c:3,d:4};
var object3={d:5,e:6};
var combined_object=object_merge(object1,object2,object3); 

combined_object and object1 both contain the properties of object1,object2,object3.

var object1={a:1,b:2};
var object2={c:3,d:4};
var object3={d:5,e:6};
var combined_object=object_merge({},object1,object2,object3); 

In this case, the combined_object contains the properties of object1,object2,object3 but object1 is not modified.

Check here: https://jsfiddle.net/ppwovxey/1/

Note: JavaScript objects are passed by reference.

Comments

1

Simplest: spread operators

var obj1 = {a: 1}
var obj2 = {b: 2}
var concat = { ...obj1, ...obj2 } // { a: 1, b: 2 }

Comments

-2
function collect(a, b, c){
    var d = {};

    for(p in a){
        d[p] = a[p];
    }
    for(p in b){
        d[p] = b[p];
    }
    for(p in c){
        d[p] = c[p];
    }

    return d;
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.