Why isn't this object being passed by reference when assigning something else to it?

I know that in JS, objects are passed by reference, for example:

function test(obj) {
    obj.name = 'new name';
}

var my_obj = { name: 'foo' };
test(my_obj);
alert(my_obj.name); // new name

But why doesn't the below work:

function test(obj) {
    obj = {};
}

var my_obj = { name: 'foo' };
test(my_obj);
alert(my_obj.name); // foo

I have set the object to {} (empty) but it still says foo.

Can any one explain the logic behind this?

Answers:

Answer

If you are familiar with pointers, that's an analogy you can take. You're actually passing a pointer, so obj.someProperty would dereference to that property and actually override that, while merely overriding obj would kill off the pointer and not overwrite the object.

Answer

Because you are overwriting the reference, not the object.

// Create a new object and assign a reference to it
// to the variable my_obj
var my_obj = { name: 'foo' };

// Pass the reference to the test function
test(my_obj);

// Assign the reference to a variable called obj
// (since that is the first argument)
function test(obj) {
// Create a new (empty) object and assign a reference to it to obj
// This replaces the existing REFERENCE
    obj = {};
}
// my_obj still has a reference to the original object, 
// because my_obj wasn't overwritten
alert(my_obj.name); // foo
Answer

Javascript lacks support for passing by reference (although objects are passed by reference and the reference is maintained as long as it is not overwrited with assignment eg. using =), but you can imitate ref keyword of C# using the following technique:

function test(obj) {
  obj.Value = {};
  //obj.Value = {name:"changed"};
}

var my_obj = { name: 'foo' };

(function ()
{
  my_obj = {Value: my_obj};
  var $return = test(my_obj);
  my_obj = my_obj.Value;
  return $return;
}).call(this);

alert(my_obj.name); // undefined, as expected
                    // In the question this returns "foo" because
                    // assignment causes dereference

Of course you can use globals and call function without arguments, in which case the references are not missed like this:

var obj = { name: 'foo' };
function test() {
    obj = {};
}
test();
alert(obj.name); // undefined

If you have all your code in closure, then things are simpler and above like globals doesn't pollute global namespace:

(function(){
    var obj = { name: 'foo' };
    function test() {
        obj = {};
    }
    test();
    alert(obj.name); // undefined
}).call(this);

The above "globals inside closure" -technique is nice if you have to port to Javascript some C# code which has ref arguments. Eg. The following C# code:

void MainLoop()
{
   // ...
   MyStruct pt1 = CreateMyStruct(1);
   MyStruct pt2 = CreateMyStruct(2);
   SwapPoints(ref pt1, ref pt2);
   // ...
}
void SwapPoints(ref MyStruct pt1, ref MyStruct pt2)
{
    MyStruct tmp = pt1;
    pt1 = pt2;
    pt2 = tmp;
}

could be ported to Javascript using something like:

(function(){
    var pt1, pt2;
    function CreateMyStruct(myvar)
    {
      return {"myvar":myvar}  
    }
    function MainLoop()
    {
       // ...
       pt1 = CreateMyStruct(1);
       pt2 = CreateMyStruct(2);
       console.log("ORIG:",pt1,pt2); 
       SwapPoints(); 
       console.log("SWAPPED:",pt1,pt2);
       // ...
    }
    function SwapPoints()
    {
        var tmp = pt1;
        pt1 = pt2;
        pt2 = tmp;
    }
    MainLoop();

}).call(this);

or if it's essential to use local variables and function arguments, then solution can be based on the first example of my answer like this:

(function(){
    function CreateMyStruct(myvar)
    {
      return {"myvar":myvar}  
    }
    function MainLoop()
    {
      // ...
      var pt1 = CreateMyStruct(1);
      var pt2 = CreateMyStruct(2);
      console.log("ORIG:",pt1,pt2); 

      (function ()
      {
        pt1 = {Value: pt1};
        pt2 = {Value: pt2};
        var $return = SwapPoints(pt1, pt2);
        pt1 = pt1.Value;
        pt2 = pt2.Value;
        return $return;
      }).call(this);

      console.log("SWAPPED:",pt1,pt2);
      // ...
    }
    function SwapPoints(pt1, pt2)
    {
      var tmp = pt1.Value;
      pt1.Value = pt2.Value;
      pt2.Value = tmp;
    }
    MainLoop();
}).call(this);

Really have to say that Javascript lacks much when it has not native ref! The code would be much simpler.

Answer

Because JavaScript actually passes objects by pass-by-copy-reference.

When you pass my_obj into your test function, a copy of a reference to that object is passed in. As a result, when you re-assign the object in test, you're really only re-assigning a copy of a reference to the original object; your original my_obj remains un-changed.

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us Javascript

©2020 All rights reserved.