JavaScript: How to pass object by value?

Javascript

Javascript Problem Overview


  • 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?

Javascript Solutions


Solution 1 - Javascript

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

Solution 2 - Javascript

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.

Solution 3 - Javascript

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)

Solution 4 - Javascript

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

Solution 5 - Javascript

Use this

x = Object.create(x1);

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

Solution 6 - Javascript

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.

Solution 7 - Javascript

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;
}

Solution 8 - Javascript

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 :

Solution 9 - Javascript

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

Solution 10 - Javascript

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

Solution 11 - Javascript

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

https://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-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);

Solution 12 - Javascript

With the ES6 syntax:

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

Solution 13 - Javascript

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() {}
  };
}

Solution 14 - Javascript

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionvol7ronView Question on Stackoverflow
Solution 1 - Javascriptuser113716View Answer on Stackoverflow
Solution 2 - JavascriptsvimreView Answer on Stackoverflow
Solution 3 - JavascriptPaul VargheseView Answer on Stackoverflow
Solution 4 - JavascriptBrandonView Answer on Stackoverflow
Solution 5 - Javascriptuser5242529View Answer on Stackoverflow
Solution 6 - JavascriptAndy EView Answer on Stackoverflow
Solution 7 - JavascriptJaredParView Answer on Stackoverflow
Solution 8 - JavascriptBrett WeberView Answer on Stackoverflow
Solution 9 - JavascriptAbubakar AhmadView Answer on Stackoverflow
Solution 10 - JavascriptGeetanshu GulatiView Answer on Stackoverflow
Solution 11 - JavascriptBeepBopView Answer on Stackoverflow
Solution 12 - JavascriptTomasz GałkowskiView Answer on Stackoverflow
Solution 13 - JavascriptRichard JP Le GuenView Answer on Stackoverflow
Solution 14 - JavascriptCon AntonakosView Answer on Stackoverflow