Skip to content

Instantly share code, notes, and snippets.

@Zirak
Created November 29, 2013 23:05
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Zirak/7713141 to your computer and use it in GitHub Desktop.
Save Zirak/7713141 to your computer and use it in GitHub Desktop.

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:

  1. The parameters are actual references, i.e. they point to a memory block.
  2. The arguments, even though they're references, are still passed by value (that's how C rolls).
  3. 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment