Why isn't this object being passed by reference when assigning something else to it?
JavascriptPass by-ReferenceJavascript Problem Overview
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?
Javascript Solutions
Solution 1 - Javascript
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.
Solution 2 - Javascript
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.
Solution 3 - Javascript
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
Solution 4 - Javascript
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.