Arrow functions bear quite the mystery for JavaScript or ES6 beginners as myself. They behave strangely in some situations and we're going to find out why.

In my quest to getting to know ES6, I used the new sexy "arrow functions" quite a lot lately. But until today I didn't know why they were necessary and that there even is a difference between arrow functions and "normal" functions 🤯. (Spoiler: No, it's not just to be quicker to write).

What are arrow functions? 🧐

Arrow functions are the new ES6-way to define functions. Let's write a function that calculates the square of a number with the ES5 syntax:

const doubleDown = function(a) {
    return a * 2;
}

In ES6, it would look something like this:

const doubleDown = (a) => {
    return a * 2;
}

There are two more arrow function features that could make this even shorter:

  • If there is only one parameter, we don't need to put the brackets
  • If the function is a one-line-return-function (as above), we don't even need the curly brackets and the return statement

Applying all of this gives us the following code:

const doubleDown = a => a * 2;

Neat! This is a sexy little ES6 function.

What is the difference between the two? 🤷‍♂️

Short version: Arrow functions don't have their own this-binding. What what? Let me try to explain how I understood it.

How arrow functions behave with objects

When we add a function as a property to an object, it's called a method. In a method, you can access the this keyword to access other properties of the same object, as follows:
this.myProperty

So, we have an object here that is an object that contains comic heroes and we want to print out a title that includes a property of the object (universe). Again, first in ES5 writing:

const comics = {
    universe: "marvel",
    heroes: ['spiderman', 'thor', 'black widow', 'deadpool'],
    
    // Regular function
    printTitle: function () {
        console.log(`hello from ${this.universe} comics`);
    },
    
    // Arrow function
    printTitleAF: () => {
        console.log(`hello from ${this.universe} comics`);
    }
}
comics.printTitle();
comics.printTitleAF();

So, here we have some heroes from a specified comic universe. We want to print a title a regular function printTitle and to compare with an arrow function printTitleAF.

Since the code is the same, the result of both should be the same, right? No, that's not the case. Here it the output of the code above:

hello from marvel comics
hello from undefined comics

This seems weird now, but will make totally sense in a minute. this in the regular function refers to the object itself, while this in the arrow function does not bind!

As you can see in the image above, the this keyword behaves differently in both functions even though they are seemingly the same.

That is because this in the case of a regular function points as expected to the object, but this in the arrow function points to an empty object.

How to use ES6 functions like a boss 😎

Nice way to write property functions in ES6

So, the arrow function notion cannot be used to define property functions. However, there is a cleaner way to write them in ES6. Just leave the colon and function keyword out:

const comics = {
    universe: "marvel",
    heroes: ['spiderman', 'thor', 'black widow', 'deadpool'],
    
    // ES6 property function
    printTitle() {
        console.log(`hello from ${this.universe} comics`);
    }
};

When you can use arrow functions

Arrow functions are useful whenever you have something that requires thisnot to be bound to function itself, but rather the context. For example passing it as a parameter to another function such as Array.forEach or setTimeout.

// ES6 version
const comics = {
    universe: "marvel",
    heroes: ['spiderman', 'thor', 'black widow', 'deadpool'],
    
    printTitle() {
        console.log(`hello from ${this.universe} comics`);
    }
    
    printHeroes() {
        // Passing an arrow function as parameter to forEach
        this.heroes.forEach(function(hero) {
            console.log(` - ${hero} is part of the ${this.universe} universe`);
        });
    }
};

That works fine because this is not bound to the function itself.

How can I do that in ES5?

Now you might be thinking "ok cool, but what if I am using ES5 in a project and need that exact behaviour?"

Well, then you need to build a dirty workaround that you can find in many places. You place this in variable:

// ES5 version
var comics = {
    universe: "marvel",
    heroes: ['spiderman', 'thor', 'black widow', 'deadpool'],
    
    printTitle: function() {
        console.log(`hello from ${this.universe} comics`);
    }
    
    printHeroes: function() {
        var that = this; //Dirty hack here
        this.heroes.forEach(function(hero) {
            console.log(` - ${hero} is part of the ${that.universe} universe`);
        });
    }
};

Summary 🙌

The whole this topic is one of the most complicated and annoying things when learning JavaScript and it behaves in strange ways. But I hope this explainer helped a little bit understanding.

When you need the context you're working in within your function when you pass it somewhere, it can be very helpful to use it. But before using arrow functions, evaluate if that is really what you need.

I found for getting a better grasp at the topic, it's useful to write some code trying it out on yourself and pretty soon it will not be that a big mystery after all.

Photo by Steinar Engeland on Unsplash