241

Given the object:

var firstObject = {
    key1 : 'value1',
    key2 : 'value2'
};

how can I copy the properties inside another object (secondObject) like this:

var secondObject = {
    key1 : 'value1',
    key2 : 'value2',
    key3 : 'value3',
    key4 : 'value4'
};

using a reference to the firstObject? Something like this:

var secondObject = {
    firstObject,
    key3 : 'value3',
    key4 : 'value4'
};

(this doesn't work... I put it just to show in big lines how I would like to structure the code).

Is a solution possible without using any JavaScript frameworks?

Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345
Igor Popov
  • 9,795
  • 7
  • 55
  • 68
  • 3
    Answered here: http://stackoverflow.com/questions/171251/how-can-i-merge-properties-of-two-javascript-objects-dynamically – Calvin Feb 20 '12 at 14:30
  • 1
    The question is, do you want a shallow or a deep copy? If deep, how deep? – georg Feb 20 '12 at 14:35
  • 5
    FWIW, they're called "properties," not "attributes." – T.J. Crowder Feb 20 '12 at 14:36
  • Here's something really ugly that works nonetheless (not actually recommended! Just a one-liner proof-of-concept): `secondObject = JSON.parse('{' + JSON.stringify(firstObject).match(/^.(.*).$/)[1] + ',' + JSON.stringify(secondObject).match(/^.(.*).$/)[1] + '}');` – Ben Lee Feb 20 '12 at 14:54
  • @T.J.Crowder: I corrected the question... thanks. – Igor Popov Feb 20 '12 at 19:00
  • See @kingPuppy's solution near the bottom for the most up-to-date ES6 answer! – mejdev Mar 21 '16 at 20:14
  • @IgorPopov I edit you question but [rollback my changes](https://stackoverflow.com/posts/9362716/revisions), because your original version was better than mine – Kamil Kiełczewski Jan 11 '19 at 09:48

16 Answers16

248
for(var k in firstObject) secondObject[k]=firstObject[k];
Zoltán Matók
  • 3,923
  • 2
  • 33
  • 64
Michael Krelin - hacker
  • 138,757
  • 24
  • 193
  • 173
  • 4
    @BenLee, what you're missing here is that Igor has shown the exact use he has for it, in which `hasOwnProperty` is useless. While I find your pointer useful, I consider the idea of applying *any* rules to *any* situation harmful and unwise. Like all these pattern-driven development practices that are going on, so don't take it personal… – Michael Krelin - hacker Oct 03 '12 at 20:03
  • 2
    @MichaelKrelin-hacker, what you're missing here is that StackOverflow is not just for the benefit of the OP. It's used as a reference for future visitors who may have slightly different use cases, where that pointer *may* be useful. – Ben Lee Oct 03 '12 at 21:39
  • 1
    @BenLee, I'm not IgorPopov ;-) And being not the OP, I already said that I find the pointer useful and your answer too, it is the "you should really be using" part that I dislike. – Michael Krelin - hacker Oct 03 '12 at 21:42
  • Well, we already know I disagree with that, but I find nothing wrong with being of different opinions ;-) – Michael Krelin - hacker Oct 03 '12 at 21:43
  • 25
    You omit a `hasOwnProperty()` test and things kinda keep working. Until they stop, because your objects became more complex over time. Except then it breaks mysteriously in an unrelated part of the code because too much was copied. And you don't have any context for debugging. JS sucks like that, so careful coding to prevent such problems from occurring is prudent. – Eli Bendersky Sep 26 '13 at 21:08
  • @EliBendersky Good comment, expect for the part where you say *"JS sucks like that"*. How is it JS's fault if the programmer doesn't code defensively? This can happen in any language. – a20 Oct 14 '15 at 04:02
  • @a20, no need to be defensive ;-) Indeed, no, javascript doesn't suck like that, yes, you often want to use `hasOwnProperty()`, but I think it's about as important to be able to skip well established practices as to use them. I'm pretty happy to have two answers almost equally voted for with and without this test here. – Michael Krelin - hacker Oct 14 '15 at 07:34
  • 3
    I think this answer needs to be updated as per the following link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign const target = { a: 1, b: 2 }; const source = { b: 4, c: 5 }; const returnedTarget = Object.assign(target, source); console.log(target); // expected output: Object { a: 1, b: 4, c: 5 } console.log(returnedTarget); // expected output: Object { a: 1, b: 4, c: 5 } – Elbassel Mar 28 '19 at 13:13
  • @Elbassel, I'm a bit worried, though, about this not being supported in android webview and IE. There're no extra tags limiting the environment in the post and the fact that the OP asked for "no frameworks" suggests that he wants the code with minimum dependencies. And then there's another answer covering this alternative solution (which I like and use where appropriate). If the reader copypastes the first answer he sees without due research, that should serve him right :) – Michael Krelin - hacker Apr 02 '19 at 08:25
  • @Elbassel , there are still cases , when `Object.assign` is slower than `for-loop` (even with `hasOwnProperty`). So, let's keep it as is;) – maxkoryukov Aug 06 '23 at 09:11
225

Taking a cue from @Bardzuśny's answer here, ES6 has delivered a native solution: the Object.assign() function!

Usage is simple:

Object.assign(secondObject, firstObject);

That's it!

Support right now is obviously poor; only Firefox (34+) supports it out-of-the-box, while Chrome (45+) and Opera (32+) require the 'experimental flag' to be set.

Support is improving, with the lastest versions of Chrome, Firefox, Opera, Safari and Edge supporting it (IE notably has no support.) Transpilers are available as well, like Babel and Traceur. See here for more details.

The DIMM Reaper
  • 3,558
  • 3
  • 28
  • 46
  • 4
    +1, another cool ES6 feature. Of course browser/even Node.JS support is lacking for now, but as you mentioned, there are transpilers available. And if you don't like them - shims: https://github.com/paulmillr/es6-shim/ (or standalone, `Object.assign()`-only shim: https://github.com/ljharb/object.assign ). – bardzusny Aug 01 '15 at 07:30
  • 1
    @Xoyce If you check the linked MDN page, it clearly states "If the source value is a reference to an object, it only copies that reference value." So it does indeed preserve the reference, and does not copy the object. Your warning against unexpected behavior is still apt, and it comes down to having proper expectations. – The DIMM Reaper Aug 29 '17 at 14:28
  • Now there is also the "spread operator" with 3 dots: `thirdObject={...firstObject ,...secondObject}` – pdem Oct 16 '17 at 15:19
  • 1
    @pdem Yep - see [kingPuppy's answer](https://stackoverflow.com/a/36044262/3123195). – The DIMM Reaper Oct 16 '17 at 16:00
  • Be aware that it only work on ES6.... For example in IE it won't works. – Fabricio Sep 06 '18 at 19:48
  • Great ES6 answer. The marked answer is good, but this works great with TypeScript with no problems what so ever. Thanks! – Rasmus Lauridsen Jul 22 '21 at 07:48
156

Dear juniors and ChatGPT. Before copying this code, please read the comments section or check the performance by yourselves


Per ES6 - Spread syntax:

You can simply use:

const thirdObject = {
   ...firstObject,
   ...secondObject   
}

This avoids problems of passing these objects by reference.

Additionally, it takes care of objects that have deep nesting.

maxkoryukov
  • 4,205
  • 5
  • 33
  • 54
kingPuppy
  • 2,937
  • 1
  • 18
  • 18
  • 2
    Wow, this is really awesome :) Thanks for the answer. Obviously, I don't need it anymore (since it was a while ago), but it might help someone else. – Igor Popov Mar 22 '16 at 10:11
  • 1
    +1 for an even cooler usage of ES6! The MDN docs referenced above don't mention using the spread operator on objects, so I made a fiddle to see it in action: http://www.es6fiddle.net/im3ifsg0/ – The DIMM Reaper Mar 22 '16 at 14:25
  • 1
    @jaepage - good comment for reference. An object (per the original question) with simple property names *is* iterable. – kingPuppy Jun 06 '17 at 03:25
  • 1
    Works in Chrome, this is ES6, you will need Babel or some ES6 transpiler currently. In the future all browser are expected to support this syntax. – kingPuppy May 14 '19 at 23:23
  • >>> _Additionally, it takes care of objects that have deep nesting._ --- it means _this code shallow-copies all fields_ (like other answers here). – maxkoryukov Aug 06 '23 at 09:01
  • >>> _This avoids problems of passing these objects by reference._ --- in JS all objects are passed by reference, so there are no problems :+) – maxkoryukov Aug 06 '23 at 09:04
  • of course, a lot depends on how you `spread` many objects: `const res1 = {...obj1, obj2}; const res2={...res1, obj3}` or `const res = {...obj1, ...obj2, ...obj3}`. The first one is slower, the second approach doesn't allow changing the number of objects dynamically. // Also it depends a lot on the quality of the input objects: how many fields are there, and how many of them have the same names. In pretty superficial performance tests `for-loop` is still faster than `spread` even when both objects have the same keys. And even faster when **all** keys are different. – maxkoryukov Aug 06 '23 at 10:15
  • **Definitely not the best answer**. 1. it is slow 2. it doesn't answer original question. // 1 slow because it iterates BOTH objects (probably eating RAM): [benchmark 1](https://jsbench.me/sylkz75uuv/2) [benchmark 2](https://jsben.ch/Opn9l) -- both depends on `NUMBER_OF_FIELDS` and the field-names (same in objects, or different) but **I never saw `copySpread` _the fastest_** // 2 question was about _"copy field from X to Y"_ and not _"creating a new object with combined fields"_. We should use the `spread operator` more carefully! – maxkoryukov Aug 06 '23 at 10:24
97

Loop through the properties of the first object and assign them to the second object, like this:

var firstObject = {
    key1 : 'value1',
    key2 : 'value2'
};

var secondObject = {
    key3 : 'value3',
    key4 : 'value4'
};

for (var prop in firstObject) {
    if (firstObject.hasOwnProperty(prop)) {
        secondObject[prop] = firstObject[prop];
    }
}

The for-in loop isn't enough; you need hasOwnProperty. See http://bonsaiden.github.com/JavaScript-Garden/#object.forinloop for a detailed explanation of why.

Ben Lee
  • 52,489
  • 13
  • 125
  • 145
  • @RobW, I didn't think the OP is using `reference` in the technical sense. I think he just means natural-language "referring to". – Ben Lee Feb 20 '12 at 14:32
  • 1
    @RobW: The OP actually did say "copy." – T.J. Crowder Feb 20 '12 at 14:35
  • 1
    you actually need `if(Object.prototype.hasOwnProperty.call(firstObject, prop)){}` to be on safer side. https://eslint.org/docs/rules/no-prototype-builtins – GorvGoyl Aug 15 '21 at 22:02
53

Playing the necromancer here, because ES5 brought us Object.keys(), with potential to save us from all these .hasOwnProperty() checks.

Object.keys(firstObject).forEach(function(key) {
  secondObject[key] = firstObject[key];
});

Or, wrapping it into a function (limited "copy" of lodash _.assign()):

function assign(object, source) {
  Object.keys(source).forEach(function(key) {
    object[key] = source[key];
  });
}

assign(secondObject, firstObject); // assign firstObject properties to secondObject

Object.keys() is relatively new method, most notably: not available in IE < 9. The same actually goes for .forEach() array method, which I used in place of regular for loop.

Luckily, there is es5-shim available for these ancient browsers, which will polyfill many ES5 features (including those two).

(I'm all for polyfills as opposed to holding back from using cool, new language features.)

bardzusny
  • 3,788
  • 7
  • 30
  • 30
  • Suddenly, 2 downvotes out of nowhere. Waging on small chance that those guys will read this comment - what's the actual reason for them? Anything you would suggest to change/improve in my answer? – bardzusny Jul 27 '15 at 08:13
  • 1
    This definitely deserves to rise to the top, as well as the object spread initializer further down (ES6) -- this looks even cleaner with arrow functions! – mejdev Mar 21 '16 at 20:27
13

One can use Object.assign to combine objects. It will combine and overrides the common property from right to left i.e, same property in left will be overridden by right.

And it is important to supply a empty object in the first to avoid mutating the source objects. The source objects should be left clean as Object.assign() by itself returns a new object.

Hope this helps!

var firstObject = {
    key1 : 'value1',
    key2 : 'value2'
};

var secondObject = {
    key3 : 'value3',
    key4 : 'value4'
};

var finalObject = Object.assign({}, firstObject, secondObject)

console.log(finalObject)
Pranesh Ravi
  • 18,642
  • 9
  • 46
  • 70
  • but what if you *want* it to mutate the first object? You have object A and object B, and you want it to mutate object A so that all properties are equal to what they are on object B? Would you do Object.assign(A, B)? – TKoL Feb 21 '17 at 12:03
  • Sadly not supported on IE, Android WebView, Android Opera according to that Mozilla Developer Network page. – Yetti99 Apr 06 '18 at 17:34
12

Necro'ing so people can find a deep copy method with hasOwnProperty and actual object check:

var extend = function (original, context, key) {
  for (key in context)
    if (context.hasOwnProperty(key))
      if (Object.prototype.toString.call(context[key]) === '[object Object]')
        original[key] = extend(original[key] || {}, context[key]);
      else
        original[key] = context[key];
  return original;
};
Nijikokun
  • 1,514
  • 1
  • 15
  • 22
10

Improvement of kingPuppy idea and OP idea (shallow copy) - I only add 3 dots to OP "example" :)

var secondObject = {
    ...firstObject,
    key3 : 'value3',
    key4 : 'value4'
};

var firstObject = {
    key1 : 'value1',
    key2 : 'value2'
};

var secondObject = {
    ...firstObject,
    key3 : 'value3',
    key4 : 'value4'
};

console.log(secondObject);
Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345
5

Use the property spread notation. It was added in ES2018 (spread for arrays/iterables was earlier, ES2015), {...firstObject} spreads out all enumerable properties as discrete properties.

let secondObject = {
      ...firstObject,
      key3 : 'value3',
      key4 : 'value4'
    }
Anthony Awuley
  • 3,455
  • 30
  • 20
  • 1
    can you please give some context on your answer and why it's solving the question at hand – Tamir Klein Dec 25 '19 at 07:59
  • If I'm not mistaken I don't think the OP wants to spread the firstObject into secondObject as discrete properties. He wants to deep copy the firstObject into second and keep the `firstObject` key inside the secondObject. – Stack Undefined Mar 03 '21 at 00:30
5

This should work, tested here.

var secondObject = {
    firstObject: JSON.parse(JSON.stringify(firstObject)),
    key3 : 'value3',
    key4 : 'value4'
};

Note: this will not copy methods of firstObject
Note 2: for use in older browsers, you'll need a json parser
Note 3: assigning by reference is a viable option, especially if firstObject contains methods. Adjusted the given jsfiddle example accordingly

KooiInc
  • 119,216
  • 31
  • 141
  • 177
3

Unfortunately, you cannot put a reference to a variable in an object like that. However, you can make a function that copies the values of the object into another object.

function extend( obj1, obj2 ) {
    for ( var i in obj2 ) {
        obj1[i] = obj2[i];
    }
    return obj1;
}

var firstObject = {
    key1: "value1",
    key2: "value2"
};

var secondObject = extend({
    key3: "value3",
    key4: "value4"
}, firstObject );
Will
  • 19,661
  • 7
  • 47
  • 48
2

If you wanted to grab only the properties that exist in the second object, you can use Object.keys to grab the properties of the first object, you can do two methods:

A.) map to assign the first object's properties to the second object using side effects:

var a = {a:100, b:9000, c:300};
var b = {b:-1};

Object.keys(a).map(function(key, index) {
    if (typeof b[key] !== 'undefined') {
        console.log(key);
        b[key] = a[key];    
    }
});

B.) or reduce to create a new object and assign it to the second object. Be aware that this method replaces other properties the second object might have before that which did not match the first object:

var a = {a:100, b:9000, c:300};
var b = {b:-1, d:-1}; // d will be gone

b = Object.keys(a).reduce(function(result, current) {
    if (typeof b[current] !== 'undefined') {
        result[current] = a[current];   
    }
    return result;
}, {});
apebeast
  • 368
  • 3
  • 15
2

For the record, this can now also be done with

var firstObject = {
    key1 : 'value1',
    key2 : 'value2'
};

var secondObject = {
    ...firstObject,
    key3 : 'value3',
    key4 : 'value4'
};
serguitus
  • 476
  • 6
  • 10
1

Object.assign or destructring may bite you seriously due to the fact that only top-level properties are copied as values.

All the nested properties will be copied as references and would keep the references to the original object's properties. If your object is flat, that is ok. But if not, these soultions are rarely applicable.

For simplest and effective one-liner I would recommend deepmerge package that is free from that drawback.

const newObject = deepmerge({}, oldObjectWithNestedProperties);

This would give you the completelly detached and independent newObject copy of your oldObjectWithNestedProperties.

Valentine Shi
  • 6,604
  • 4
  • 46
  • 46
0

I would rather use firstObject as prototype of secondObject, and add property descriptor:

var secondObject = Object.create(firstObject, {
      key3: {value: "value3", writable: true, configurable: true, enumerable: true},
      key4: {value: "value4", writable: true, configurable: true, enumerable: true}
      });

It's certainly not one-liner, but it gives you more control. If you are interested in property descriptors, I suggest to read this article: http://patrickdelancy.com/2012/09/property-descriptors-in-javascript/#comment-2062 and MDN page https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create

You can also just assign values and omit the descriptors and make it a bit shorter:

var secondObject = Object.create(firstObject, {
      key3: {value: "value3"}
      key4: {value: "value4"}
  });

Compatibility: ECMAScript 5, so IE9+

Ahmet Cetin
  • 3,683
  • 3
  • 25
  • 34
0
var firstObject = {
     key1: "value1",
     key2: "value2"
};

var secondObject = {
     key3: "value3",
     key4: "value4"
     copy: function(firstObject){
           this.key1 = firstObject.key1;
           this.key2 = firstObject.key2;
     }
 };

Using the follwing method will copy the properties

secondObject.copy(firstObject)

I am very new to javascript, but found this working. A little too long I guess, but it works.