So you have a javascript function.
function func () {}
It accepts a value.
function func (param) {}
And you call that function.
var n = 4;
func(n);
Is the variable passed by reference, or by value? And to further burden your life, how about now:
function func (obj, n) {
obj.a = 2;
n = 3;
}
var o = { a : 0 },
n = 1;
console.log(o.a, n); //0 1
func(o, n);
console.log(o.a, n); //2 1
Seemingly, it looks like primitive values are passed by value, and objects are passed by reference. That is false. Proving that is simple:
function swap (obj0, obj1) {
var tmp = obj0;
obj0 = obj1;
obj1 = tmp;
}
var o0 = { a : 4 },
o1 = { a : 'foo' };
console.log(o0.a, o1.a); //4 'foo'
swap(o0, o1);
console.log(o0.a, o1.a); //4 'foo'
If objects were indeed passed by reference, then o0
and o1
would have switched. But the thing is, obj0
and obj1
, and n
and swap
and func
and console
and anything in the entire js world is not a pointer. You never get your hands on a block of memory - you always deal with the value of pointers, not with pointers themselves. A working version in C would look something like:
void swap (int *a, int *b) {
int tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
Notice that in here we have several unique properties:
- The parameters are actual references, i.e. they point to a memory block.
- The arguments, even though they're references, are still passed by value (that's how C rolls).
- To say "give me the value", you have to explicitly say "give me the value", like
*a
or*b
.
The last point is critical, it goes to the heart of the matter, it gets to the confusion: Even though it looks like you have a pointer, you always deal with values. You can do obj0 = { ... }
without a problem, because obj0
is not a reference, it's the result of that reference, it's what the reference leads to, it's the reference value.
And that's what js is: Pass by reference value. Never touch a reference, always its value. However, and this is an important however, you also never pass by value or even touch a non-reference-value. You'll see why in a bit.
So why does o1
change when we change obj1
inside the function?
Why, that's a good question, invisible reader! That's because of the difference between mutable and immutable data (which is nothing to do with references).
Mutable data is something like an array, any object at all. It's blocks of memory which are prone to change. You have ways to express these changes - arr[0] = 7
or obj.foo = 'bar'
.
Immutable data is something like 4 or a string. It's just...there. When you do 4 + 1
, you don't change 4. You can't change 4. It's a number, it's always 4. You can't in any way express a change to data like that. Unlike arrays which have things like pop
, there's no way to express any sort of mutation. So when you do var n = 4; n += 1
, the value of n
doesn't change - it's simply reassigned. Because again, the value of n
(which is 4), cannot change - you can instead make n
point to a different value.