109
  • When passing objects as parameters, JavaScript passes them by reference and makes it hard to create local copies of the objects.

    var o = {};
    (function(x){
        var obj = x;
        obj.foo = 'foo';
        obj.bar = 'bar';
    })(o)
    

    o will have .foo and .bar.

  • It's possible to get around this by cloning; simple example:

    var o = {};
    
    function Clone(x) {
       for(p in x)
       this[p] = (typeof(x[p]) == 'object')? new Clone(x[p]) : x[p];
    }
    
    (function(x){
        var obj = new Clone(x);
        obj.foo = 'foo';
        obj.bar = 'bar';
    })(o)
    

    o will not have .foo or .bar.


Question

  1. Is there a better way to pass objects by value, other than creating a local copy/clone?
vol7ron
  • 40,809
  • 21
  • 119
  • 172
  • 3
    What is your use case for needing this? – jondavidjohn Sep 27 '11 at 18:39
  • 2
    Programming fun. Seeing if new JS engines have addressed this (technically, it is passing the reference by value), but mainly for fun. – vol7ron Sep 27 '11 at 18:40
  • 1
    See [Is JavaScript a pass-by-reference or pass-by-value language?](http://stackoverflow.com/questions/518000/is-javascript-a-pass-by-reference-or-pass-by-value-language) - JavaScript doesn't pass by reference. Like Java, when passing objects to a function, it passes by value, but the value is a reference. See also [Is Java pass by reference?](http://stackoverflow.com/questions/40480/is-java-pass-by-reference). – Richard JP Le Guen Sep 27 '11 at 18:41
  • 1
    As far as I'm aware you can't pass objects by value. Even if there was, it would in effect be doing the cloning you're referring to above, so there's nothing to gain that I can see. Other than perhaps saving 3 lines of code. – Vala Sep 27 '11 at 18:42
  • 1
    @vol7ron Yes, they have addressed it by implementing a language design characteristic correctly. – jondavidjohn Sep 27 '11 at 18:46
  • It looks lke the answer to this may one day be `var copy := copiedObj;` Or at least they've been tinkering with the idea. – Erik Reppen Aug 22 '12 at 13:59
  • @ErikReppen: it's those tinkerings which I never stay up to date with - thanks for posting – vol7ron Jan 24 '13 at 22:09

15 Answers15

66

Not really.

Depending on what you actually need, one possibility may be to set o as the prototype of a new object.

var o = {};
(function(x){
    var obj = Object.create( x );
    obj.foo = 'foo';
    obj.bar = 'bar';
})(o);

alert( o.foo ); // undefined

So any properties you add to obj will be not be added to o. Any properties added to obj with the same property name as a property in o will shadow the o property.

Of course, any properties added to o will be available from obj if they're not shadowed, and all objects that have o in the prototype chain will see the same updates to o.

Also, if obj has a property that references another object, like an Array, you'll need to be sure to shadow that object before adding members to the object, otherwise, those members will be added to obj, and will be shared among all objects that have obj in the prototype chain.

var o = {
    baz: []
};
(function(x){
    var obj = Object.create( x );

    obj.baz.push( 'new value' );

})(o);

alert( o.baz[0] );  // 'new_value'

Here you can see that because you didn't shadow the Array at baz on o with a baz property on obj, the o.baz Array gets modified.

So instead, you'd need to shadow it first:

var o = {
    baz: []
};
(function(x){
    var obj = Object.create( x );

    obj.baz = [];
    obj.baz.push( 'new value' );

})(o);

alert( o.baz[0] );  // undefined
user113716
  • 318,772
  • 63
  • 451
  • 440
  • 3
    +1, I was going to suggest `Object.create` in my answer too, but I didn't want to stretch to explaining the shallowness of the copy ;-) – Andy E Sep 27 '11 at 18:52
  • +1, I forgot about this. I did try `var obj = new Object(x)`. To me, I would think that `new Object(x)` would perform `Object.create(x)` by default - interesting – vol7ron Sep 27 '11 at 19:10
  • 1
    @vol7ron: Yeah, `new Object(x)` just spits back out the same object *(as you probably noticed)*. It would be nice if there was a native way to clone. Not sure if there's anything in the works. – user113716 Sep 27 '11 at 20:26
57

Check out this answer https://stackoverflow.com/a/5344074/746491 .

In short, JSON.parse(JSON.stringify(obj)) is a fast way to copy your objects, if your objects can be serialized to json.

Community
  • 1
  • 1
svimre
  • 851
  • 11
  • 24
  • 3
    I tend to avoid this as the objects can't always be serialized and because in mid-aged browsers like IE7/8, `JSON` Is not included and needs to be defined -- might as well be more descriptive with a name like `Clone`. However, I suspect my opinion may change in the future, since JSON is more heavily integrated into non-browser based software like databases and IDEs – vol7ron Jul 19 '14 at 16:16
  • 1
    If there are no functions and date objects, the JSON.parse solution seems to be best. http://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-clone-an-object – Herr_Hansen Apr 14 '16 at 12:08
  • Really?!? Serialize to JSON just to create an object copy? Yet another reason to hate this absurd language. – RyanNerd May 27 '18 at 10:15
  • 1
    Serializing JSON is really a fast way to copy it? According to NodeJS documentation JSON manipulation is most CPU intensive task. https://nodejs.org/en/docs/guides/dont-block-the-event-loop/#blocking-the-event-loop-json-dos – harshad Oct 30 '18 at 04:22
  • Object.create() didn't work for me on NodeJS. Your solution solved my problem. – Andresa Martins Apr 15 '21 at 13:32
45

Here is clone function that will perform deep copy of the object:

function clone(obj){
    if(obj == null || typeof(obj) != 'object')
        return obj;

    var temp = new obj.constructor(); 
    for(var key in obj)
        temp[key] = clone(obj[key]);

    return temp;
}

Now you can you use like this:

(function(x){
    var obj = clone(x);
    obj.foo = 'foo';
    obj.bar = 'bar';
})(o)
j2ko
  • 2,479
  • 1
  • 16
  • 29
Paul Varghese
  • 1,635
  • 1
  • 15
  • 30
32

Use Object.assign()

Example:

var a = {some: object};
var b = new Object;
Object.assign(b, a);
// b now equals a, but not by association.

A cleaner example that does the same thing:

var a = {some: object};
var b = Object.assign({}, a);
// Once again, b now equals a.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

Brandon
  • 530
  • 4
  • 7
  • 6
    Better: `var b = Object.assign({}, a);` – Bergi Mar 03 '16 at 00:27
  • Agreed. Updating answer accordingly. Also, not every browser supports the assign() method. Depending on your compatibility requirements, using a polyfill like the one on the MDN may be required. – Brandon Mar 16 '16 at 22:27
  • 3
    @Brandon, in the very link you provided, it gives a warning for deep cloning: "For deep cloning, we need to use other alternatives because Object.assign() copies property values. If the source value is a reference to an object, it only copies that reference value." – pwilcox Nov 22 '17 at 16:56
  • 2
    This works but keep in mind that it doesn't perform deep copy any objects contained inside `a` will be copied as reference. – Stoinov Mar 10 '19 at 16:26
  • 1
    @Stoinov I think you meant to say `...objects contained inside a will be copied as referenced VALUES` – emersonthis Dec 02 '22 at 03:24
24

Use this

x = Object.create(x1);

x and x1 will be two different object,change in x will not change x1

Rahul Kumar
  • 5,120
  • 5
  • 33
  • 44
user5242529
  • 249
  • 2
  • 2
  • I end up using Object.assign(). For simple test case, .create() works but for more complex (which I cant find the pattern yet), it still refer to the same address. – Coisox Sep 03 '18 at 17:04
  • 2
    It won't only change if the values of the object are not stored by reference i.e they are premitive data types like number or boolean. For example, consider the code below a = {x:[12], y:[]}; b = Object.create(a); b.x.push(12); console.log(a.x); – Jjagwe Dennis Sep 13 '18 at 08:01
  • I tried printing both objects after delete operation it reflects in both object – Ninad Kambli Mar 25 '21 at 14:43
17

You're a little confused about how objects work in JavaScript. The object's reference is the value of the variable. There is no unserialized value. When you create an object, its structure is stored in memory and the variable it was assigned to holds a reference to that structure.

Even if what you're asking was provided in some sort of easy, native language construct it would still technically be cloning.

JavaScript is really just pass-by-value... it's just that the value passed might be a reference to something.

Andy E
  • 338,112
  • 86
  • 474
  • 445
  • 2
    Hey AndyE! I'm not confused by that, I was hopeful that JS would do the cloning by default. There are large inefficiencies in self cloning, so if the engine did it, I'm sure it'd be better. I doubt the need/demand exceeds the benefit, though. – vol7ron Sep 27 '11 at 19:13
  • 15
    In JS when people say by reference instead of by value they mean the value is like a pointer rather than a duplicate. That's pretty well-established lingo. – Erik Reppen Aug 22 '12 at 14:03
  • 5
    @Erik: in my humble opinion, I think it's better to define it more clearly so as not to confuse newcomers to the language. Just because something is well-established doesn't mean it's appropriate or even technically correct (because it isn't). People say "by reference" because it is easier for them to say that than explaining how it really works. – Andy E Aug 23 '12 at 09:34
  • 6
    The value is a reference to a location in memory. Ultimately you're still acting on the same item in memory rather than working with a copy. How is making that distinction ambiguous supposed to help newcomers? This is how it's explained in a lot of tech books including O'Reilly's Authoritative Guide which is now on its fifth (OT: and very weakly updated) edition. – Erik Reppen Aug 23 '12 at 16:28
  • 1
    @AndyE I did a bit more reading to see what the fuss about. IMO, this is kind of like the issue of whether JS has "true" OOP or we can properly call something a "method" compared to other languages. I'm not actually certain it would be feasible to treat vars as writing directly to the same object in memory rather than overwriting its copied pointer in a closure-based language with performance-slaying branching of assignment operator behavior. The only real behavior distinction in what we mean in JS vs other languages is in what happens when you use the assignment operator. – Erik Reppen Aug 23 '12 at 17:15
  • AndyE and @ErikReppen Nearly 10 years later and I think you’ve both highlighted the confusion and communicated concept & implementation better than I have when recently trying to explain it to a confused newcomer. *face palm* – vol7ron Mar 05 '20 at 12:57
9

ES6
Using the spread operator like obj2 = { ...obj1 } Will have same values but different references
ES5
Use Object.assign obj2 = Object.assign({}, obj1)

Geetanshu Gulati
  • 692
  • 8
  • 13
  • 2
    New to javascript here. Spread operator creates new value instead of copying by reference? So why was this downvoted? – jo3birdtalk Apr 21 '19 at 13:53
  • 4
    At the first glance, it works out for me. But I discover it is only to the first layer of the variable. For instance, it works out when `let a = {value: "old"}` `let b = [...a]` `b.value = "new"`, and a will be `{value: "old"}`, b will be `{value: "new"}`. But it doesn't work out when `let a = [{value: "old"}]` `let b = [...a]` `b[0].value = "new"`, and a will be `[{value: "new"}]`, b will be `[{value: "new"}]`. – Brady Huang Apr 29 '19 at 16:52
  • 2
    yes it does shallow copy. If you have nested object you nee to do deep copy. For simplicity you can use clone and deepClone functions of lodash – Geetanshu Gulati Jan 24 '20 at 13:37
8

As a consideration to jQuery users, there is also a way to do this in a simple way using the framework. Just another way jQuery makes our lives a little easier.

var oShallowCopy = jQuery.extend({}, o);
var oDeepCopy    = jQuery.extend(true, {}, o); 

references :

Community
  • 1
  • 1
Brett Weber
  • 1,839
  • 18
  • 22
  • Ah -- you discovered this old question :) I think the original question was more of an exploration of the JS language. It seems even my terminology was weak back then since my example was of a *deep copy* rather than a *clone*. But it seems objects/hashes may only be passed by reference, which is common in scripting languages – vol7ron Apr 09 '14 at 20:21
  • 1
    :) Came across it looking for the exact functionality. I had a data object i needed to copy for editing before submitting while persisting the original object. I prefer the native JS solution and will be using it in my own base library, but the jQuery solution is my temporary fix. The accepted answer is fantastic. :D – Brett Weber Apr 09 '14 at 20:38
8

Javascript always passes by value. In this case it's passing a copy of the reference o into the anonymous function. The code is using a copy of the reference but it's mutating the single object. There is no way to make javascript pass by anything other than value.

In this case what you want is to pass a copy of the underlying object. Cloning the object is the only recourse. Your clone method needs a bit of an update though

function ShallowCopy(o) {
  var copy = Object.create(o);
  for (prop in o) {
    if (o.hasOwnProperty(prop)) {
      copy[prop] = o[prop];
    }
  }
  return copy;
}
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • 1
    +1 For the "always passes by value" although I prefer using [Call by Object Sharing](http://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_sharing) (as opposed to "Call by Value [of the Reference]") and promote "the value" to "the object itself" (with the note that the object is not copied/cloned/duplicated) as references are just an implementation detail and are not exposed to JavaScript (or directly mentioned in the specification!). –  Sep 27 '11 at 18:53
  • I had a problem adding properties to an object i am receiving from a remote connection ( I thought that might be the problem that I am not able to add any property to that object ) so i tried this shallowcopy function and got this error - Object prototype may only be an Object or null at var copy = Object.create(o); any idea how to solve my problem – Harshit Laddha Jul 06 '14 at 05:33
  • Is this not a deep copy? – River Tam Sep 22 '14 at 22:21
  • @RiverTam No, it's not a deep copy, because it doesn't clone the objects within the objects. However, you can **easily** make it a deep copy just by making it recursively call itself on each of the sub-objects. – ABPerson Mar 07 '20 at 23:58
7

Actually, Javascript is always pass by value. But because object references are values, objects will behave like they are passed by reference.

So in order to walk around this, stringify the object and parse it back, both using JSON. See example of code below:

var person = { Name: 'John', Age: '21', Gender: 'Male' };

var holder = JSON.stringify(person);
// value of holder is "{"Name":"John","Age":"21","Gender":"Male"}"
// note that holder is a new string object

var person_copy = JSON.parse(holder);
// value of person_copy is { Name: 'John', Age: '21', Gender: 'Male' };
// person and person_copy now have the same properties and data
// but are referencing two different objects
Abubakar Ahmad
  • 2,567
  • 1
  • 18
  • 16
  • 2
    Yes, this is an option for simple convert/re-convert. Generally, working with strings is very inefficient; though, I haven't evaluated the performance of JSON parsing in some time. Keep in mind that while this works for simple objects, objects that contain functions as values, will lose content. – vol7ron Mar 03 '17 at 15:23
  • 1
    I've actually benchmarked this and have seen others do it, and because of efficiencies in javascripts json engine this method really is one of the fastest ways you can do this without bringing in a big library, writing a lot of code, or not doing a true deep copy. – Robert Hafner Oct 31 '20 at 05:41
3

I needed to copy an object by value (not reference) and I found this page helpful:

What is the most efficient way to deep clone an object in JavaScript?. In particular, cloning an object with the following code by John Resig:

//Shallow copy
var newObject = jQuery.extend({}, oldObject);
// Deep copy
var newObject = jQuery.extend(true, {}, oldObject);
Community
  • 1
  • 1
  • The question is about JavaScript, not the jQuery library. – j08691 Aug 12 '16 at 13:28
  • 1
    True, for people who cannot use Jquery for whatever reason this wouldn't help them. However, as Jquery is a javascript library, I think it'll still help most javascript users. –  Aug 15 '16 at 10:43
  • It won't help any of the programmers trying to do it on the server. So - no. It is not a valid answer. – Tomasz Gałkowski Jan 27 '17 at 12:09
3

With the ES6 syntax:

let obj = Object.assign({}, o);

Tomasz Gałkowski
  • 1,841
  • 4
  • 24
  • 39
  • 4
    Very good mention @galkowskit. The biggest issue (better: *thing to note*) with the the `Object.assign` is that it doesn't perform a deep copy. – vol7ron Jan 27 '17 at 21:02
1

When you boil down to it, it's just a fancy overly-complicated proxy, but maybe Catch-All Proxies could do it?

var o = {
    a: 'a',
    b: 'b',
    func: function() { return 'func'; }
};

var proxy = Proxy.create(handlerMaker(o), o);

(function(x){
    var obj = x;
    console.log(x.a);
    console.log(x.b);
    obj.foo = 'foo';
    obj.bar = 'bar';
})(proxy);

console.log(o.foo);

function handlerMaker(obj) {
  return {
   getOwnPropertyDescriptor: function(name) {
     var desc = Object.getOwnPropertyDescriptor(obj, name);
     // a trapping proxy's properties must always be configurable
     if (desc !== undefined) { desc.configurable = true; }
     return desc;
   },
   getPropertyDescriptor:  function(name) {
     var desc = Object.getOwnPropertyDescriptor(obj, name); // not in ES5
     // a trapping proxy's properties must always be configurable
     if (desc !== undefined) { desc.configurable = true; }
     return desc;
   },
   getOwnPropertyNames: function() {
     return Object.getOwnPropertyNames(obj);
   },
   getPropertyNames: function() {
     return Object.getPropertyNames(obj);                // not in ES5
   },
   defineProperty: function(name, desc) {

   },
   delete:       function(name) { return delete obj[name]; },   
   fix:          function() {}
  };
}
Richard JP Le Guen
  • 28,364
  • 7
  • 89
  • 119
  • Richard, I'm a little late to responding :) but I think I never did for a few reasons: I was looking in syntactic sugar that gave JS the ability to pass objects in different ways; your answer looked long, and I was hung up on your use of "proxy". 3 years later and I'm still hung up on the use. Perhaps I didn't pay enough attention in class, but like networking, I thought proxies in CS are supposed to act as an intermediary. Perhaps it is here as well and I'm not correctly thinking about what it's a mediating between. – vol7ron Jul 19 '14 at 16:30
0

If you are using lodash or npm, use lodash's merge function to deep copy all of the object's properties to a new empty object like so:

var objectCopy = lodash.merge({}, originalObject);

https://lodash.com/docs#merge

https://www.npmjs.com/package/lodash.merge

Con Antonakos
  • 1,735
  • 20
  • 23
  • A deep copy should also include events, I'm not too familiar with lodash, does it mirror events to a new object? – vol7ron Mar 01 '16 at 01:07
0

The simplest answer is:

let objectB = { ...objectA }
Jacek Dziurdzikowski
  • 2,015
  • 2
  • 13
  • 20