I'm new to JavaScript (though experienced in C++), and today, I wrote something like this:
function foo(bar) {
bar = "something else";
}
var x = "blah";
foo(x);
alert(x); // Alerts with "blah", but I was expecting it to alert with "something else"
This confused me a lot, as I've been watching some JavaScript videos by Douglas Crockford, and remember him saying something like "JavaScript is always pass by reference".
The way I can explain this situation is that JavaScript passes references to objects, but those references are copied. This would mean in the foo
function, I am assigning a new reference to bar
, which then goes out of scope, leaving to reference that x
has left untouched. Essentially we start with:
x ---->"blah"
Then when foo
is called, bar
references the same data:
x ---->"blah"
bar -----^
So when "something else" is assigned to bar
, this happens:
x ---->"blah"
bar ---->"something else"
Is that an accurate model of what is actually happening in JavaScript, or am I missing something else?
As an extra question, is there any way to say, change the data referenced by this variable? Is this a situation that comes up often, or can it be easily avoided?
Edit:
Douglas Crockford in the video I watched says "objects are always passed by reference they're not passed by value", which is correct, but arguments to functions are passed by value, it's just the reference is passed by value.
"JavaScript is always pass by reference" is, well, a [white] lie and a confusion of terms. While there is some "gray area", I go by these definitions of evaluation strategies.
Here are my arguments and reasoning. If you hold a different view, make sure that you can at least support it.
Call By Reference means (to many people) that assigning to a parameter affects bindings in the caller.
In call-by-reference evaluation (also referred to as pass-by-reference), a function receives an implicit reference to a variable used as argument, rather than a copy of its value. This typically means that the function can modify (i.e. assign to) the variable used as argument—something that will be seen by its caller.
This is not the case in JavaScript, as the original post has noted in the observed behavior. Re-assigning a parameter (which can be thought of as a local variable with a dynamically supplied value) has no affect on any supplied arguments.
Sometimes, "Call By Reference" is [confusingly] used to mean "Call By Sharing" or "Call By Value [of the Reference]" as discussed next; true Call By Reference is found in languages like C++ and VB, but not JavaScript.
JavaScript's calling conventions can be discussed entirely in terms of Call By [Object] Sharing semantics.
All JavaScript objects are values; and all primitive values (which are a subset of all values) are immutable.
The semantics of call by sharing differ from call by reference in that assignments to function arguments within the function aren't visible to the caller, so e.g. if a variable was passed, it is not possible to simulate an assignment on that variable in the caller's scope. However since the function has access to the same object as the caller (no copy is made), mutations to those objects, if the objects are mutable, within the function are visible to the caller, which may appear to differ from call by value semantics.
An example of these Shared mutations is provided in ultrayoshi's answer and can be explained simply: when an expression (such as a variable access) evaluates to an object, and said object is passed to a function, no copy/clone is made.
While the terminology "Call By Value [of the Reference]" is often used to describe the behavior, it should be noted that JavaScript does not have "references" (or "non-reference" values) in the sense of Java/C# so this terminology is subtly misleading - at least it's not saying Call By Reference, with it's various connotations, and many people understand a low-explanation.
In call-by-value, the argument expression is evaluated, and the resulting value is bound to the corresponding variable in the function .. If the function or procedure is able to assign values to its parameters, only its local copy is assigned — that is, [any variable] passed into a function call is unchanged in the caller's scope when the function returns.
Because only a "reference" to an object is passed (and not a copy/clone of said object), the semantics are merely that of Call By Sharing. However, I avoid this terminology in JavaScript because then it brings in unnecessary implementation details and also introduces a divide in how implementations pass objects vs primitive values.
The description "call-by-value where the value is a reference" is common (but should not be understood as being call-by-reference); another term is call-by-sharing.
Thus, when I'm talking about calling conventions in JavaScript,
I prefer to use Call By Sharing to discuss the behavior and I avoid Call By [Value/Reference] as they have too many different "meanings" and drag in unnecessary implementation details.