Wednesday, June 26, 2013

A Look Into How Parameters Are Passed In JavaScript

I recently came across a question on StackOverflow about how JavaScript handles parameters, if they are passed by value or by reference. There seemed to be a lot of confusion and misinformation about what is actually happening behind the scenes.

TLDR; All arguments are passed by value in JavaScript, however, when dealing with non-primitive datatypes like objects and arrays a variable is created that points to the location of the object memory that is then is passed into the function. This means that changes to the variable inside the function will affect the original object's values. Once the argument is reassigned (e.g. arg = {} ) the variable now has the location of the new object in it so the original variable is no longer changed when the value changes.

By Reference vs. By Value

Let's start be defining exactly what by passing a variable reference and by value actually means.

By Reference

If a parameter is being passed into a function by reference it means that only a reference to the variable is being passed into the function is passed as the argument. The variable in the function and the variable that is passed into the function are actually pointing to the same location in memory. Put simply, if the value is modified inside the function the original value is also changed.

By Value

If a value is being passed into a function by value it means that a copy of the variable is being passed into the function. The variable in the function and the variable that is passed into the function are two separate variables. Put simply, if the value is modified inside a function the original value will remain unchanged.

By The Book

According to MDN:
The parameters of a function call are the function's arguments. Arguments are passed to functions by value. If the function changes the value of an argument, this change is not reflected globally or in the calling function. However, object references are values, too, and they are special: if the function changes the referred object's properties, that change is visible outside the function.

Huh?

Let me try to describe this with pictures. First let's create a variable that is a simple object literal:

var obj = { foo : 'foo' };

When we do this the variable obj is really just a reference to a location in memory that holds the actual object:



If a function is invoked and obj is passed into the function as an argument that reference is copied and passed into the function. In other words, the reference is being passed by value:

doSomething( obj );

This is where things start to get interesting. The pointer to the object is passed into the function call by value. In other words, a copy of the pointer is created and passed into the function call. We now have two variables that point to the same object:




At this point if the argument is modified inside the function call the changes will be reflected on the original varialbe outside of the function call. However if the argument is reassigned inside the function the reference will no longer point to the original object and changes inside the function will no longer affect the variable outside the function call:


function doSomething( obj ){

   obj = { baz : 'baz' }; //reassigns the pointer

}

After reassignment our objects in memory look like this:





What about primitives?

At this point you might be asking yourself, what about primitive datatypes like strings and numbers? The truth is that the point is quite moot since primitives are immutable, which means they cannot be changed. When a primitive is changed a new variable is created and reassigned to the original. Since this reassignment happens every time a primitive is changed it doesn't matter, the primitive will never point to the original location in memory once its changed so you'll always end up with the same behavior as if it was being passed by value.
Fork me on GitHub