Is Javascript a pass-by-value language, or a pass-by-reference language?
It's an important question, and (in practice) the answer is actually: neither. Actually, technically, the answer is: Javascript is purely pass-by-value. The reason that I say 'neither' is because 'pass-by-value' really does not explain Javascript's variable passing behaviour in any meaningful way. Lets dig into why.
First, just to get them out of the way, primitives (Number, String, etc) are always pass-by-value.
function changeValue(toChange) {
toChange = 2;
}
var num = 1;
console.log(num);
changeValue(num);
console.log(num);
// Output:
// 1
// 1
It only gets weird when you get into object passing. Now, technically, Javascript is pass-by-value. But take a look at this code:
function changeValue(toChange) {
toChange.value = 2;
}
var obj = {value: 1};
console.log(obj.value);
changeValue(obj);
console.log(obj.value);
// Output:
// 1
// 2
So, ok, clearly it's pass-by-reference, no? If it were pass-by-value, we would be unable to change the value of the passed-in object, we'd be changing a copy of that value inside changeValue()
.
Well, now that you're convinced Javascript is pass-by-reference, look at this:
function changeValue(toChange) {
toChange = {value: 2};
}
var obj = {value: 1};
console.log(obj.value);
changeValue(obj);
console.log(obj.value);
// Output:
// 1
// 1
Whaaat? In this case, we've assigned a new object to toChange
. In pass-by-reference, one would expect obj
to reflect this change, but it does not. What in the world... ?
So, here's what's happening: Javascript is actually passing a reference to obj
by value. (Say that again...?) Javascript is effectively copying the reference, not the referred-to object. When you call changeValue(obj)
, you're creating two (completely independent) references to the same object. Outside of the function, you have obj
, and inside the function, you have toChange
. They both refer to the same object in memory, but the reference variables themselves are independent.
That means that if you modify an individual property, you'll be dereferencing the actual object, and you'll be modifying the property directly on the object itself. That's why, in the first example, the outer obj
variable reflects the change to the inner toChange
variable.
When you assign a new object to toChange
, though, you're changing the reference entirely. You're saying 'hey, toChange
variable, point at this new object over here, please.' This does not affect obj
's reference in any way. obj
is still referring to our original object. The upshot of this is: toChange
and obj
are entirely independent, and modifying toChange
will no longer affect obj
.
So, what's the answer? Technically (language internals), it's pass-by-value. In practice, I'd put it like this: Javascript is pass-by-reference for objects, with the small exception that assigning a new object will break the reference.