DEV Community

Kelvin Wangonya
Kelvin Wangonya

Posted on • Updated on • Originally published at wangonya.com

'this' and arrow functions

Arrow functions were introduced in ES6 as a new syntax for writing Javascript functions. Thanks to their short syntax, they encourage the use of small functions, which make code look cleaner (and () => just looks cooler 😄).

As a beginner just getting to wrap my head around ES6 syntax, I began using arrow functions everywhere without really understanding how they worked. As you might expect, I ended up running into some problems, especially with the this keyword.

this can get a bit confusing sometimes as its value varies depending on the function's execution context, and on the mode (strict or non-strict). Much has been written about the ins and outs of that so I'll just focus on one thing:

How this works in arrow functions

In a regular function, this refers to the object when defined as a method of an object. We can therefor do:

const brunch = {
    food: 'Dim sum',
    beverage: 'Jasmine tea',
    order: function() {
        return `I'll have the ${this.food} with ${this.beverage} please.`
    }
}
Enter fullscreen mode Exit fullscreen mode

Calling brunch.order() will return "I'll have the Dim sum with Jasmine tea please."

Let's edit that and use an arrow function for order::

const brunch = {
    food: 'Dim sum',
    beverage: 'Jasmine tea',
    order: () => {
        return `I'll have the ${this.food} with ${this.beverage} please.`
    }
}
Enter fullscreen mode Exit fullscreen mode

This time, calling brunch.order() returns "I'll have the undefined with undefined please." Both this.food and this.beverage return undefined.

It worked with the normal function, so what's going on? In the normal function, this was our order object. When using an arrow function, this is not bound to anything and it just inherits from the parent scope which in this case is the window. Adding a console.log(this) before the return in the arrow function returns a Window object, so its looking for Window.food and Window.beverage which will obviously both be undefined.

Arrow functions are therefor not suited as object methods.

Another common problem area would be with event handlers. Here's an example:

// change button colour on click
<style>
.on {background: red;}
</style>

<button id="click">Toggle</button>

<script>
const button = document.querySelector('#click');
button.addEventListener('click', function() {
    console.log(this); // button
    this.classList.toggle('on');
});
</script>
Enter fullscreen mode Exit fullscreen mode

In the code above, this refers to the button. Clicking on the button toggles the colour as expected. Change the function to an arrow function:

// change button colour on click
<style>
.on {background: red;}
</style>

<button id="click">Toggle</button>

<script>
const button = document.querySelector('#click');
button.addEventListener('click', () => {
    console.log(this); // Window { ... }
    this.classList.toggle('on');
});
</script>
Enter fullscreen mode Exit fullscreen mode

and this becomes the browser's window attribute. Clicking the button will give a TypeError error. If you rely on this in an event hanlder, a regular function may be necessary.

So, as cool and popular as arrow functions may be, its best to understand how they work, and to know when to and not to use them.

Top comments (11)

Collapse
 
codevault profile image
Sergiu Mureşan

The problems are not limited to event handlers, JQuery's utility functions are also affected by this. The project I am working on relies on JQuery quite a bit so I am defaulting to regular functions and, when need be, I am using arrow functions.

I like the event handler example here, really helps understand what is up with arrow functions. I wonder if that's why the newer JS functions pass the element you are checking through their arguments instead of through this.

Collapse
 
wangonya profile image
Kelvin Wangonya

Hi! Thanks for reading. Yeah, the problems certainly aren't limited to what I've written here. For example, they also can't be used as constructors.

"I wonder if that's why the newer JS functions pass the element you are checking through their arguments instead of through this." Which newer functions are you referring to?

Collapse
 
codevault profile image
Sergiu Mureşan • Edited

Nevermind, I always thought that some of the array functions like filter and some are from ES2015 which, on further investigation, turned out to be false

Although, they work nicely with the arrow functions since they all take their values not from this but from the parameter of the functions you give it.

Collapse
 
kayis profile image
K

Yes, the capturing of this by arrow functions is rather cumbersome.

Somehow I managed to use it either in a functional programming context where there is no this needed or with classes and class fields, where I can write something like class A { x = "world!"; m = () => "Hello, " + this.x; }.

Collapse
 
wangonya profile image
Kelvin Wangonya

Nice! Maybe you should do an article on that when you find the time. Expound on it a little more, I'd be interested (or have you already?).

Thanks for reading

Collapse
 
kayis profile image
K

On what specifically?

Collapse
 
anurbol profile image
Nurbol Alpysbayev • Edited

Just use VSCode and utilize Intellisense. You'll be given appropriate hints and gradually you'll learn all the quirks (not actually) of this.

Collapse
 
wangonya profile image
Kelvin Wangonya

Hi! Thanks for the tip.

Collapse
 
neelam28 profile image
Neelam

Thanks so much for this post. I now have a clear(somewhat, as "this" is very complex to understand) idea about the relationship between arrow functions and the "this" keyword :)

Collapse
 
hasheendeberry profile image
Hasheen DeBerry

Very helpful. Thank you!

Collapse
 
wangonya profile image
Kelvin Wangonya

I'm glad you found the post useful Hasheen. Happy coding!