Arrow Functions – When Not to Use Them

Arrow functions can bring a couple of problems if you don’t fully understand how they work. I’ll show you a few common mistakes. By the end of this article, you should have a better understanding of when it makes sense to use regular functions.

What are Arrow Functions?

Arrow functions are a more concise way of writing function expressions. Arrow functions are anonymous and change the way this binds in functions. Their goal is to simplify scoping and readability.

In regular functions, the this keyword binds to the execution context (global, function or eval). Arrow functions on the other hand don’t provide their own this binding (it retains the this value of the enclosing lexical context).

The problem with “this”

As we pointed out before, arrow functions do not bind this like regular function expressions.

An arrow function does not have its own this. The this value of the enclosing lexical scope is used; arrow functions follow the normal variable lookup rules. So while searching for this which is not present in the current scope, an arrow function ends up finding the this from its enclosing scope.

Let’s look at some examples

// Default function declaration
function getName() {
  return 'Fernando';

// Arrow function declaration
const getName = () => 'Fernando';
// Array map using the regular function declaration
const names = function( name ) {
  return name;
} );

// Array map using arrow functions
const names = ( name ) => name );

As you can see, it’s much simpler to declare Arrow Functions. There are a few ways to write these examples. MDN has a list showcasing more varieties.

Object Methods

Suppose we have an object where we store an email content and I have a method to update this content.

const email = {
  content: 'This is a sample content',
  updateContent: ( newContent ) => {
    this.content = newContent;

You would think that email.content would get updated but that won’t happen. The keyword this is in this case is referencing window and not the email object.

This is easily fixable by using regular functions instead like so:

const email = {
  content: 'This is a sample content',
  updateContent: function( newContent ) {
    this.content = newContent;

You can test both cases here and here.


Similarly to the example above, prototypes will interpret this as the window object. Let’s look at the example.

class Article {
  constructor( title ) {
    this.title = title;
    this.shared = false;

Article.prototype.share = () => {
  return this.shared = true;

Just as the previous example the method share will not work due to the scope of this. And again, it’s a simple solution.

Article.prototype.share = function() {
  return this.shared = true;

Callback Functions

Most commonly used are callback functions. This in particular got me pulling my hairs for about 15 minutes before I understood what the arrow functions were doing.

const button = document.getElementById( 'my-button' );

button.addEventListener( 'click', () => {
  this.classList.toggle( 'active' );
} );

This won’t work because again, this is referencing window and not the button. However, on this example we have a different way to fix it.

We could pass the event to the callback function and use the target like so:

button.addEventListener( 'click', ( e ) => {
  e.currentTarget.classList.toggle( 'active' );
} );

You can learn more about event.currentTarget here.


I hope I was able to demonstrate the differences in scope when you are using function(){} versus () => {} and how to get around them.

Let me know if there’s anything I could have added here and I’ll make sure to update this post.

By Fernando Claussen

Fernando Claussen is a WordPress developer who brings his front-end background to help businesses thrive. He began his development career in a small agency in Brazil working with the finest companies in Brazil that ranged from small shops to hotel chains. Fernando is especially known for his contributions to the Trew Knowledge team and the GDPR WordPress plugin.

Leave a Reply