Why isn't this object being passed by reference when assigning something else to it?
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.
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.
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
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.