Where Not to Use Arrow Functions

CSCI-UA.0480-008

Arrow Functions are Useful!

In arrow functions, this is whatever this refers to in the context where the arrow function was created. So, the code below, which produces a bunch of undefined's, can be fixed by converting the anonymous function into an arrow function. →


const counter = {numbers: [1, 2, 3, 4], animal:'owl'};
counter.count = function() {
    this.numbers.forEach(function(n) {
        console.log(n, this.animal + (n > 1 ? 's' : ''));
    });
};
counter.count(); // uh-oh... prints undefined 4 times!!!!

Fixed by arrow functions:


counter.count = function() {
    this.numbers.forEach((n) => {
        // this refers to the this in count!
        console.log(n, this.animal + (n > 1 ? 's' : ''));
    });
}; // ah, saved by an arrow function

Where Not to Use Arrow Functions

Well, if arrow functions are so great, why don't we use arrow functions all of the time?

There are some places where they don't work quite right.

  • creating constructors
  • creating methods
    • either on object literals
    • or on prototypes
  • (not relevant now, but) creating addEventListener callbacks where you want this to refer to the element that generated the event


But why not?

Remember, arrow functions do not bind this to a new value, and instead gets its this from the enclosing scope

Arrow Functions Cannot be Constructors

In the following code, we try to use an arrow function as a constructor.


const Cat = (name) => {
    this.name = name;
}

Creating the function works fine, but if we try to use it with new:


var c = new Cat();

We get…


var c = new Cat();
        ^
TypeError: Cat is not a constructor

Instead, use the usual function declaration to create constructors:


function Cat(name) {
    this.name = name;
}

Arrow Functions as Methods

What is the output of this code?


function Cat(name) {
    this.name = name;
}
Cat.prototype.meow = (() => {
    console.log(this.name, 'meows');
});
var c = new Cat('paw newman');
c.meow();

undefined meows
  • …because arrow functions do not bind a new value to this
  • again, this remains the same as the this in the containing context / scope
  • (which, in this case is the global object)

Arrow Functions as Methods on Object Literals

What's the output of this code?

const cat = {
    sound: 'meow',
    meow: () => {console.log(this.sound);}
};
cat.meow();

// once again...
undefined

Arrow Functions and addEventListener

To be complete… be careful when using arrow functions and addEventListener

Starting with this code:


const button = document.createElement('button');
document.body.appendChild(button).textContent = 'Click Me';

The following listeners alert different messages!


// alerts window object (essentially global)
button.addEventListener('click', () => {alert(this)});

// alerts button element
button.addEventListener('click', function()  {alert(this)});
  • if you want this in your event handler to reference the element event's target element, then use function expressions
  • …because arrow functions don't create their own this, and instead use the this from the surrounding context