JavaScript parameter passing

How does JavaScript pass parameters into functions?  I have seen a lot of confusion and misunderstanding on this topic for several years.  Even among people that consider themselves JavaScript experts.  I have seen articles and posts that state Pass-By-Reference and I have seen others that state it sometimes uses Pass-By-Value or Pass-By-Reference depending on the argument type.  These are all wrong, so I thought I would take a stab at explaining exactly how it works and why it is so misunderstood.

To start with lets look at the several different methods used by various programming languages to handle parameter passing.  The two most common are Pass-By-Value and Pass-By-Reference.  There are some other less common methods such as Pass-By-Name that I have used, but we’ll skip over those since the are not applicable here.

Pass-By-Value

In the Pass-By-Value method, parameter variables are copied onto the stack and then made available to the function.  Once the function returns, and the stack is popped, then the copies are gone.  This means that the the variables in the outer scope will never be modified, no matter what the function my do to them.  This provides a nice safety net to ensure that a function does not accidentally modify something that it shouldn’t.

Pass-By-Reference

In the Pass-By-Reference method, a reference (pointer) to the variable is created, placed on the stack, and made available to the function.  Once the function returns, and the stack is popped, then the reference is gone.  However  unlike in the Pass-By-Value method, any changes made to the referenced variable will be visible in the outer scope.  This can be more performant when dealing with large data structures since you do not have to create copies of the entire value.

JavaScript (aka ECMAScript)

So which method is used by JavaScript?  JavaScript always passes function arguments by value.  But I’m sure you have seen many cases where functions modify the objects in the outer scope.  This is why people often think that Pass-By-Reference is being used.  To see what is going on, lets look at a few examples.

Example #1 – primitive

var outCount = 5;

function example1(inCount) {
    inCount = inCount + 1;
}

example1(outCount);
console.log("Output: " + outCount);
Output: 5

In this example the console is logging “5” and not “6”.  The changes within the example1 function are not visible in the outer scope.  This shows that the parameter was passed in by value.

Example #2 – object

var bob = {firstname:"Bob", lastname:"Smith"};

function example2(person) {
    person.firstname = "Sally";
}

example2(bob);
console.log("Output: " + bob.firstname);
Output: Sally

In this example the console is logging “Sally”. The changes made within the example2 function are visible in the outer scope. So it appears the the parameter was passed by reference. But let’s look at another example before we jump to conclusions.

Example #3 – object part duex

var bob = {firstname:"Bob", lastname:"Smith"};

function example3(person) {
    person = {firstname:"Sally", lastname:"Smith"};
}

example3(bob);
console.log("Output: " + bob.firstname);
Output: Bob

In this example the console is logging “Bob” rather than “Sally” like in the previous example.  The changes made within the example3 function are not visible in the outer scope.  So in this example it appears that the parameter was passed by value and not by reference.  We need to look under the covers and see what is going on.

Under the covers

In all three examples above JavaScript is passing the parameter into the function by value.  The reason that the behavior looks different is because of the type of variables we are passing and the types of modifications we are making, which are different in each case.

The variable used in example #1(outCount) is an integer number.  It is stored internally in memory as 8 bytes to represent the value.  This type of variable is referred to as a primitive.  When we pass the value into our function (as inCount) JavaScript is making a copy of the 8 bytes and putting them on the stack for the function to access (as inCount).  The copy is then thrown away after the function returns.

The variable in examples #2 and #3 (bob) is an object.  It is stored internally as two parts.  One is a block of memory on the heap that contains the representation of the object.  The other is the reference to the object in memory.  This second part is what is actually stored in the variable.  When we pass this variable into our function (as person) JavaScript is making a copy of the reference and putting that on the stack of the function to access.  The copy of the reference is then thrown away after the function returns. However, the contents of the object which are accessed by the references (both bob and person) are shared in both the inside and outside scope and it is never copied.

This means that when we make changes to the contents of an object passed into a function (which is what example #2 is doing) then those changes will persist after the function returns. If however we make changes to the reference itself, such as pointing it to a new object (which is what example #3 is doing) then that change is discarded after the function returns and the outer scope is unaffected.

Conclusions

JavaScript always passes function parameters by value.  If the variable being passed is an object, then the function has access to the object contents in a shared memory location through a reference.  Changes to the object contents will be visible in the outer scope after the function returns, however changes to the reference itself will not be visible in the outer scope after the function returns.

Examples of primitives in JavaScript include numbers, booleans and strings.  But be wary, because if you instantiate your variable with the new operator then it will be an object rather than a primitive and it may not behave the way you expect!

var x = new String();    // This string is an object

I hope you now have a better understanding of what is going on in JavaScript functions. Mis-understanding how this works can (and does) led to bugs that can be difficult to diagnose. Hopefully your new understanding will save you time and trouble in the future. If so, leave me a note to let me know!

1 thought on “JavaScript parameter passing”

Leave a Reply

Your email address will not be published. Required fields are marked *