Diving into functions. Passing by reference is a lie!

JavaScript

Functions are one of the most basic features of JavaScript. Have you ever wondered how exactly do they work? After all, they are just a special kind of objects. If you are curious, dig into them with me in this article!

The basics of functions

Speaking practically, a function is a subprogram that can be called in another place of the code. It has a function body which is a sequence of statements. It can have values passed to it as arguments. The function can also return a value. In JavaScript, they are objects inheriting from Function.prototype. If you would like to know more about prototypes themselves, look into one of my previous articles: Prototype. The big bro behind ES6 class. Check out this piece of code:

A default return value of a function is undefined. It is a little different when you use the new keyword though because then the default value is the instance of the object created (the one that this points to in the function).

Passing arguments to functions

Arguments passed to functions are always passed by value. It means, that if the function changes the value of an argument, it won’t be reflected outside of the scope of a function. It applies to both primitives (like strings) and objects.

You might have read before, that objects are passed by reference in JavaScript. If you look closely at the example above, you can see that we can’t overwrite an obj variable from inside of the function, which would have happened in a “pass by reference” situation. This common misconception arises from a fact, that when we assign an object to a variable, the actual thing that is stored is a reference to the object (to a place in memory that it is stored in). The variables themselves don’t contain the actual value of the object. The function is given just a copy of that reference, that is in fact passed by value to it – not a reference to a variable outside. Thanks to that behaviour, we can mutate the objects that we pass to our functions, but we can’t overwrite the variable:

If you are still not convinced of my point of view on always passing all variables by values, check out this issue on You Don’t Know JS repo or a discussion on Stack Overflow.

Ways to create a function

There are actually quite a few ways to create a function. They generally fall into one of a few groups:

Function declaration

It uses a special syntax for functions declaration with the function keyword followed by an obligatory name of the function. Its greatest advantage is that it is hoisted to the top of the scope, which means that it can be invoked before its declaration:

The created function is named, therefore the function object holds its name. It might be useful when viewing the call stack in the debugging process.

Function expression

It looks similar to function declaration but can be a part of a larger expression. The main difference compared to the function declaration is that a function name can be omitted here. Functions created with a function expression won’t be hoisted to the top, therefore they can’t be invoked before their declaration:

Anonymous functions

Since we can omit the function name, it can cause them to be “anonymous”. This behaviour was changed in the ES6 though. Now, they are given a name from their syntactic position:

In previous versions of JavaScript, it would be an empty string. If you look at the babel compiler, it even changes the anonymous functions to the named ones. The more important name for the JavaScript interpreter would be the one explicitly provided:

If you look closer right into the property descriptor, the name of a function can’t be overwritten:

Since it is configurable, you can define it using  Object.defineProperty function,:

Function constructor

Calling the function constructor creates a new object inheriting from the Function.prototype. You can create a function dynamically this way, but it is less efficient than using function expression, or the function statement. Functions created this way are named “anonymous“:

In this constructor, the last argument is always the function body and the previous ones are the arguments.

Another important thing about creating functions with the function constructor is the fact that functions created this way do not create closures to their creation contexts. They are always created in the global scope and will only be able to access their own local variables and the global ones.

Arrow functions

Another important concept connected to the way that functions are created are arrow functions. You can read about them in one of my previous articles: What is “this”? Arrow functions.

Arguments object

As said before, functions can have arguments passed to them. In the function scope, you have an object called arguments containing all of them.

As you can see, it is not exactly an array. You can create one with it though:

It is possible because arguments are iterable:

You can pass any amount of arguments to a function and just use some of them in the function declaration. The arguments object will hold all of them though:

In the past we used a property of a function, also called arguments, but this is now deprecated:

Summary

And this is all for today! I hope that you learned a lot today and gained a solid understanding of what are functions in JavaScript. Since functions are such a broad topic, there will be more on them in the future: for example about closures. Take care!

Comments (1)

Leave a Reply

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