Javascript: Pass by reference or value?
|
If you search the web for the topic of how JavaScript passes parameters into functions, you'll get a mixture of thoughts on it, many of which are, unfortunately, wrong. These thoughts are more than opinions; they're based on the experiences of the people making the statements. But unfortunately, too often a decision is made only on partial information. I'll get to the point: Regardless of what you might read, JavaScript always passes by value and does not pass by reference. JavaScript does not use a mixture, passing by reference for objects and arrays, and value otherwise.
First, here's a demonstration. Create a function such as this:
function reftest(a) {
a = 10;
}
That's simple enough; the function takes a parameter, a, and sets its value to 10. Now for the test: What will happen to the object passed in when you call this function?
x = [1,2,3];
y = 5;
z = "abc"
reftest(x);
alert(x);
reftest(y);
alert(y);
reftest(z);
alert(z);
When I ran this code, I saw three alert boxes open in sequence, each one displaying the values of the original, unchanged values: [1,2,3], 5, and "abc". In other words, the function did not change these variables. If JavaScript had used pass-by-reference, the values of these variables would all have changed to the integer value 10. Thus, we may conclude that JavaScript passes by value. But why do some people claim JavaScript uses a mixed paradigm? Because this pass-by-value feature has interesting effects when you pass in an object. Look at this example:
function reftest2(a) {
a.x = 10;
}
c = {x:1, y:2}; If you go strictly by what I just said, you might assume that the reftest2 function gets a copy of the object passed into it, and modifies the x member of that copy, leaving the original unchanged. But that's not what happens! The x member of c does indeed get changed by the function from 2 to 10. From this, it would be easy to surmise that JavaScript uses pass-by-reference when dealing with objects. But it still doesn't. Try calling the original reftest function, passing the an object, and you'll see the object doesn't change. The confusion here results in what exactly the value of a variable is. When an object is passed into a function, its internal address is what gets passed in. That's the "value" of the object. Thus when the function modifies the x member of the object it received, it ends up modifying the same x member as that in the original object. While this might seem like pass-by-reference, it's still pass-by-value. (If you're a C programmer, this should be totally familiar to you. C uses only pass-by-value as well, and you run into similar behavior when you pass an array into a function.) So why does it matter? Because you need to know exactly what the functions you create will do in all cases; otherwise you might end up with some nasty bugs! |


Comments (12)
to: Jeff Cogswell
re: javascript pass-by-whatever
Thu 8/30/2007 2:13 pm
Well just to make trouble -- you're wrong!
// The confusion here results in what exactly the value of a variable is. When an object is passed into a function, its internal address is what gets passed in. //
So you *say*; you have *special knowledge*. I would put it, "javascript automatically passes objects by reference". In c,
----------------------------------------
#include
typedef struct {
int bingo, bongo;
} ASTRUCT;
void afunc(ASTRUCT a) {
a.bingo = 8;
}
void bfunc(ASTRUCT *a) {
a->bingo = 8;
}
void main (void) {
ASTRUCT a;
a.bingo = 7;
afunc(a);
printf("%d\n",a.bingo);
bfunc(&a);
printf("%d\n",a.bingo);
}
----------------------------------------
It prints
7
8
I had to *tell* C to do pass-by-reference with the & and * operators.
If javascript *on its own* decides to treat a class of variables -- objects -- differently than others, and treats them as pass by references -- then that's what it's doing. Mumbo-jumbo about "its internal address" doesn't clarify; the language is defined by its syntax, and what it does in the privacy of its own compilation/interpretation is its problem; what is does *from our point of view* is treat objects differently than plain-old-variables.
-- best wishes
j.g. owen * * * * * * * * * * * * * * * * * * *
web: http://owenlabs.home.att.net/
email: owen_bda4@yahoo.com
* * * * * * * * * * * * * * * * * * * * * * * *
Posted by j.g. owen | August 30, 2007 2:36 PM
Thanks for the comment!
Good points, and good examples. I certainly can't argue with the idea that we can perceive JavaScript as passing objects by reference. I do, however, hesitate to actually say it does.
The reason is that if I'm creating a library and somebody else is using the library, I want to make absolutely sure that the other person and I are both clear on how my library handles the objects passed into its functions. As long as we're both clear, then choice of words "pass by value" vs "pass by reference" may not matter, I suppose. But if we're not clear because I say one thing and the user interprets it another way, then that's just asking for bugs.
However, what is perhaps more important than simple terminology is that people completely understand the mechanism. Can a function in JavaScript change the variable itself (rather than just its members)? Here's some code that attempts to do it, but fails:
a = {x:10, y:20};
function myfunction(q) {
q = {member1: 'a', member2: 'b'};
}
myfunction(a);
alert(a.member1);
In this case, is the object passed in by reference or by value? While it may not matter whether in my mind I consider it by value or by reference, the fact remains that the object "a" does *not* change into {member1: 'a', member2: 'b'}. Understanding this is vital to writing correct, bug-free code in JavaScript, whether we call it passing by value or by reference.
Posted by Jeff Cogswell | August 30, 2007 4:25 PM
to: Jeff Cogswell
re: javascript pass-by-whatever
Wed 9/05/2007 3:37 pm
Well just to footnote this fascinating discussion, I was perusing "Java in a Nutshell" (O'Reilly 1999) -- and under the heading "Terminology: Pass by Value" (p 74) author Flanagan agrees with Cogswell:
"Java ... is a 'pass by value' language. However, when a reference type is involved, the value that is passed is a reference. But this is not the same as pass-by-reference. If Java were a pass-by-reference language, when a reference type was passed by a method, it would be passed as a reference to the reference."
Which, for me, is gratifying in a way; I like a traditional obfuscation. I will still go to the grave believing a reference that is passed is indeed passed by reference, but obviously will do so as an ignorant non-believer....
... I just realized this note may help to fuel any Javascript/Java confusions lingering about -- but I can't help but feel that's somehow appropriate....
-- best wishes,
j.g. owen * * * * * * * * * * * * * * * * * * *
web: http://owenlabs.home.att.net/
email: owen_bda4@yahoo.com
* * * * * * * * * * * * * * * * * * * * * * * *
Posted by j.g. owen | September 5, 2007 3:39 PM
It seems to me that there is flaw in your example. When you have the function variable 'a' and you assign to it, whatever it was referring to before doesn't change, the variable 'a' just gets a new value. This means that you can have multiple variables referring to 'a', and when you reassign 'a', that variable will now refer to a different object. Other variables that referenced the original object will still reference the original object. If however 'a' is an object and you set a property of that object, it will be reflected on the original object, because 'a' isn't "reassigned", the value of its property is. When languages are "pass by value" my understanding is that they make copies of the variables being sent to a function. Pass by reference just means that instead of making copies of all the values in an object, a reference to the object is passed. I wholeheartedly agree with what I perceive to be your *main* point. It doesn't matter what we call it, it is important to understand how making changes to a function parameter will affect the variable that was passed.
Posted by adam83 | January 10, 2008 11:42 PM
Hi,
First, I'd like to point out that:
1. JavaScript is not Java, nor is it a form of Java.
2. JavaScript is not C, but that's kind of obvious.
So, while principle definitions may apply, the specifications are different and implementation of the specification are open to interpretation.
JavaScript, or ECMAScript (The official name) has it's own specifications which can be found at http://www.ecma-international.org/publications/standards/Ecma-262.htm.
When passing a variable to a function, it in fact makes it's own local scope variable containing the value and/or properties/attributes depending on the parameter type passed in to a function.
*All parameters are passed by value*
Paramaeter Passing Rules:
a. Value type = pass by value (Creates new local variable)
b. Object type = pass by value (Creates new local variable) the address of the object, which in "effect" is reference to the original object, but the address is still passed by value.
c. You are unable in any way to pass a value type by reference.
Note: Reference types exist in JavaScript, but are internal use only by definition of the specification.
If you pass in an Object (ECMA-262: ECMAScript Language Specification - An Object is an unordered collection of properties. Each property consists of a name, a value and a set of attributes.) the properties of the object become the properties of the local scope variable. But the properties point to the original properties.
Creating a new Object in the local scope does just that, creates a new Object.
************snippet from Jeff Cogswell*******
a = {x:10, y:20};
function myfunction(q) {
q = {member1: 'a', member2: 'b'};
}
myfunction(a);
alert(a.member1);
**************************
Your code above creates a "NEW" Ojbect for local scope variable q.
However, you could do the following and it would add the properties member1, member2 to the original Object.
************************
a = {x:10, y:20};
function myfunction(q) {
q.member1= 'a';
q.member2= 'b';
}
myfunction(a);
alert(a.member1);
*********************
If you want to return multiple values from a function, wrap your value type variables in an object, pass in the object, do something, then assign the object properties to your local variables upon return from the function.
Here is a quick sample I threw together.
--------------Sample Code----------
// v is local scope to foo1
// if v is a data type the assignment will work on the local scope variable.
// if v is an object, assignment will create a new local scope v.
function foo1(v) {
write("In Foo1");
write("before v=" + v);
v = 30; // assigns to local scope v
write("after v=" + v);
write("v.x=" + v.x);
write("v.y=" + v.y);
write("a=" + a);
write("a.x=" + a.x);
write("a.y=" + a.y);
write("b=" + b);
write("b.x=" + b.x);
write("b.y=" + b.y);
write("--------");
}
// w is local scope to foo2
// if w is a Object the assignment will work on the local scope variable and the original properties.
// if w is a data type, assignment will fail silently.
function foo2(w) {
write("In Foo2");
write("before w=" + w);
write("before w.x=" + w.x);
write("before w.y=" + w.y);
w.x = 20; // create/assign property x - points to the original property if it exists
w.y = 55; // create/assign property y - points to the original property if it exists
write("after w=" + w);
write("after w.x=" + w.x);
write("after w.y=" + w.y);
write("a=" + a);
write("a.x=" + a.x);
write("a.y=" + a.y);
write("b=" + b);
write("b.x=" + b.x);
write("b.y=" + b.y);
write("--------");
}
function write(msg) {
document.write("
" + msg);
}
////////////////////////
// a and b are global scope
var a = 1;
var b= new Object;
b.x = 2;
write("(1)==== foo1(a)");
foo1(a);
write("After foo1(a)");
write("a=" + a);
write("a.x=" + a.x);
write("a.y=" + a.y);
write("b=" + b);
write("b.x=" + b.x);
write("b.y=" + b.y);
write("*****************************");
write("(2)=== foo1(b)");
foo1(b);
write("After foo1(b)");
write("a=" + a);
write("a.x=" + a.x);
write("a.y=" + a.y);
write("b=" + b);
write("b.x=" + b.x);
write("b.y=" + b.y);
write("*****************************");
write("(3)=== foo2(a)");
foo2(a);
write("After foo2(a)");
write("a=" + a);
write("a.x=" + a.x);
write("a.y=" + a.y);
write("b=" + b);
write("b.x=" + b.x);
write("b.y=" + b.y);
write("*****************************");
write("(4)=== foo2(b)");
foo2(b);
write("After foo2(b)");
write("a=" + a);
write("a.x=" + a.x);
write("a.y=" + a.y);
write("b=" + b);
write("b.x=" + b.x);
write("b.y=" + b.y);
write("*****************************");
var c = 5; // original c value
var d = 6; // original d value
var e = 7; // original d value
var k = new Object; // create a new object wrapper
k.x = c; // creates a NEW property
k.y = d; // creates a NEW property
k.z = e; // creates a NEW property
write("(5)=== foo2(c)");
write("c=" + c);
write("d=" + d);
write("e=" + e);
write("k.x=" + k.x);
write("k.y=" + k.y);
write("k.z=" + k.z);
foo2(k);
write("After foo2(k)");
write("c=" + c);
write("d=" + d);
write("e=" + e);
write("k.x=" + k.x);
write("k.y=" + k.y);
write("k.z=" + k.z);
c = k.x; // assign to local scope c
d = k.y; // assign to local scope d
e = k.z; // assign to local scope e
write("After assigning to local c,d,e");
write("c=" + c);
write("d=" + d);
write("e=" + e);
write("*****************************");
////////////////////////
--------------RESULTS--------------
(1)==== foo1(a)
In Foo1
before v=1
after v=30
v.x=undefined
v.y=undefined
a=1
a.x=undefined
a.y=undefined
b=[object Object]
b.x=2
b.y=undefined
--------
After foo1(a)
a=1
a.x=undefined
a.y=undefined
b=[object Object]
b.x=2
b.y=undefined
*****************************
(2)=== foo1(b)
In Foo1
before v=[object Object]
after v=30
v.x=undefined
v.y=undefined
a=1
a.x=undefined
a.y=undefined
b=[object Object]
b.x=2
b.y=undefined
--------
After foo1(b)
a=1
a.x=undefined
a.y=undefined
b=[object Object]
b.x=2
b.y=undefined
*****************************
(3)=== foo2(a)
In Foo2
before w=1
before w.x=undefined
before w.y=undefined
after w=1
after w.x=undefined
after w.y=undefined
a=1
a.x=undefined
a.y=undefined
b=[object Object]
b.x=2
b.y=undefined
--------
After foo2(a)
a=1
a.x=undefined
a.y=undefined
b=[object Object]
b.x=2
b.y=undefined
*****************************
(4)=== foo2(b)
In Foo2
before w=[object Object]
before w.x=2
before w.y=undefined
after w=[object Object]
after w.x=20
after w.y=55
a=1
a.x=undefined
a.y=undefined
b=[object Object]
b.x=20
b.y=55
--------
After foo2(b)
a=1
a.x=undefined
a.y=undefined
b=[object Object]
b.x=20
b.y=55
*****************************
(5)=== foo2(c)
c=5
d=6
e=7
k.x=5
k.y=6
k.z=7
In Foo2
before w=[object Object]
before w.x=5
before w.y=6
after w=[object Object]
after w.x=20
after w.y=55
a=1
a.x=undefined
a.y=undefined
b=[object Object]
b.x=20
b.y=55
--------
After foo2(k)
c=5
d=6
e=7
k.x=20
k.y=55
k.z=7
After assigning to local c,d,e
c=20
d=55
e=7
*****************************
Posted by h. shank | January 25, 2008 11:02 AM
j.g. owen:
Think of it this way. An object is a normal local int that holds a number which happens to be an address to a spot in memory large enough to hold your object.
Now, when you pass this to a function, you are NOT passing an object into the function, you are passing an int which holds the address of an object. Now, when you call a.x, javascript looks up the address contained in this int value, and manipulates the data at that address, NOT the value passed into the function. Therefore any object that happens to hold this address would point to the same spot, and will reflect whatever changes were made to member variables.
However, if you tried to modify the address of a. a = 0x43232343, then this would NOT modify the original address of a in the calling function. It would modify a local int value that lives on the stack for the called function.
So, if you were to make a new object, say a RegExp object: a = new RegExp("blaa");, what is happening is that memory is allocated on the heap to make room for this RegExp object, and the address is assigned to the local variable a, which is on the stack of the called function, and the original a in the calling function is not affected.
If it were pass by reference, the original a in the calling function would become a RegExp object, and point to the new location in memory, but since it isnt, the original a is still whatever object it was before the function was called, and it still points to its original address.
C is exactly the same way. A pointer is nothing more than an unsigned int that holds a memory location. This is why you have to use the * operator to modify its value. If you had a pointer (int* a) and you said a=3, your not modifying the value that a points to, your modifying the address that a holds.
Posted by computrius | January 29, 2008 9:58 AM
Well according to me the object in java are passed by references.
1.Example 1
Let c = {x:1, y:2};
function reftest1(a)
{ a.x = 10; }
reftest1(c)
alert(c.x)
The answer will be 10;
It changes the value of a.x
2.Example 2
But when u do
Let c = {x:1, y:2};
function reftest2(a)
{ a = 10; }
reftest2(c)
alert(c.x);
The value of x = 1;
This is because as in both case 'c' is pointer to an object {x1:1, y:2} so when we call reftest1(c) then a is also pointing to the same object hence the a.x is same as c.x;
But in case 2 we do a=10; this means now a is pointing to object which is 10. But c is still pointing to same object hence the value does not change.
Posted by pawan kumar | April 17, 2009 10:35 AM
Hi Kumar, thanks for the excellent example.
It's been a year and a half since I wrote this blog, and now that I re-read it, I'm realizing it really just comes down to how one defines the term "by reference."
I would argue that your second example proves that it's pass-by-value. The reason is that if JavaScript used pass-by-reference, then in the second example, after calling reftest2, the variable c would now have the value 10. But it doesn't. The variable c is unchanged.
What your second example tells me is that the function has allocated its own copy of the variable that is passed into it, and has assigned that variable the name "a", and that variable has the value {x:1, y:2}. The function then replaces that value with the value 10. But then when the function returns, we find that the original variable, c, is unchanged. Thus we can see that the function received a copy of the variable and that copy was given the same value as the variable passed in.
However, your first example forces me to adjust what I said just a bit. What I just said isn't *quite* right. The first example shows that when the function allocated its own variable (called "a") and that variable received a copy of the value of the object passed in, it's not *quite* just a copy. Instead, it's a pointer to this object {x:1, y:2}.
This actually tells us a great deal about how JavaScript works, thanks to these two really good examples you came up with. What it tells us is that the value of an object is its address -- just like in C++. Of course, in JavaScript and other higher-level languages we usually try to avoid the notion of pointers, but in a case like this it appears it's unavoidable.
Here, then, is what it looks to me is happening:
1. When you pass an object such as {x:1, y:2} into a function, you're passing a pointer to that object.
2. The function creates a new variable and stores that pointer int the variable.
3. The function can change the value of the variable to something of a different type without modifying the original variable passed in.
4. But if the function modifies the object, since it's a pointer, the original object does get modified.
In my *opinion* (and at that point that's all it is), this implies "pass by value". The "value" of an object is a pointer to the object.
However, that said, this concept is exactly how C++ implements references. They're souped up pointers. So I agree one could argue that this is a way of implementing pass-by-reference. But under the hood, I would argue it's still pass by value.
Posted by Jeff Cogswell | April 17, 2009 11:50 AM
Hi
x=0;
reftest(x)=undefined because it does not return
alert(x) will show 0
alert(reftest(x)) will show undefined
x and reftest(x) are stored separately
Firstly you cannot reassign literal values in any language as far as I am aware.
Secondly your function did not return a value so you could not reassign:
x = reftest(x)
It is not surprising that your 3 alert boxes showed what you put in.
Whatever went on inside those functions was local scope. a was a new variable inside the function and the value you passed did nothing.
Not sure if that clarifies ??
Posted by kitty | April 24, 2009 8:18 AM
>> When I an this code, I saw three alert boxes ... Thus, we may conclude that JavaScript passes by value.
Thus nothing! What your browser and JavaScript engine are doing is anecdotal, not definitive.
Anybody confused over how Java or JavaScript passes arguments is a hobbyist with very little knowledge or experience. There is no confusion over how these languages pass object arguments (notwithstanding the woefully uninformed).
What is confusing is the term pass-by-value. Confusion will only occur when talking about the precise definition of the pass-by-value pattern.
Whether I copy the object or pass in a reference, it's all pass-by-value. If you really want pass-by-reference, you have to support changing the reference value itself, not just what it refers to.
Person eve;
Person bob;
Person alice;
foo( bob ) ....
To have bob refer to eve when foo returns, would require pass-by-reference semantics.
PRACTICALLY speaking, talking about Java and JavaScript as being pass-by-reference for objects works just fine.
Posted by Rick O'Shay | August 16, 2009 5:39 PM
if (years.length != gs.length) {
var gsYears = years; // do not want to make any changes to the years array.....gsYears will be spliced
// get the difference of the two arrays
var gsr = gsYears.length - gs.length;
alert(years.toString());
// remove elements from the tempYears array, to match with the gs array
gsYears.splice(0, gsr);
alert(years.toString());
// create data array for gsLine
for (j=0; j gsLine.push([gsYears[j], gs[j]]);
}
}
well, 'years' is the original array.. in this case, the splice method is supposed to splice the gsYears i guess, not the years.....but it did splice up both the arrays...
:S...is it passed by value? i guess not!
Posted by newb | August 30, 2009 9:08 PM
Newb, thanks for the example.
Since I wrote this blog two years ago, I've heard from a lot of people, and I've basically come to this conclusion: It really doesn't matter whether you call it "pass by value" or "pass by reference." What matters is that you understand what is going to happen.
I would still argue that the arrays are passed by value -- not the value of the array contents, but the value of the address of the array (just like in C). But again, it doesn't matter. What matters is that when you program in any language you understand how variables are treated when they're passed around.
But your example is not just about passing by value vs. reference but about how variables are copied in JavaScript. The key in your example is this line:
var gsYears = years
Are you really making a duplicate array that has all the same values, or are you simply creating what's essentially a second name for the same variable? Indeed, based on what happens in your code, you're not creating a new copy of the array at all, but just creating a second name for it. You have one array, and it's called both years and gsYears. (Dare I say you've created two references to the same variable.)
These are the important factors to understand in any language, because if we don't, it would be too easy to introduce bugs in our code (bugs that can be extremely difficult to track down and fix!).
(And your example is indeed interesting -- I'm going to write a blog post about how variables are copied (or not) in JavaScript. I'll add a comment here when the blog post is ready.)
Posted by Jeff Cogswell | September 2, 2009 9:10 AM