Why you should avoid using arrow functions to define class methods
Tags: javascript, beginners, webdev, typescript
Published: 2022-09-22 19:33:07

In this article, we'll learn about JavaScript class methods and why we shouldn't use arrow functions in methods definition.

Classes have been introduced to JavaScript as part of ES6. Before that, for create a class we used a function where we were describing a JavaScript object with logic in methods and properties using `this` notation.

Let’s create a simple class with some methods:
```javascript
class Pet {
  name = 'dog';

  getName() {
    return this.name;
  }
}
```

There is only one property `name` and one method `getName` in this `Pet` class. Method definition has been set to default function declaration.

Classes can be created this way, but it wasn't possible in ES5 before. Let’s see how we could create the same class in ES5:
```javascript
"use strict";
var Pet = (function () {
    function Pet() {
        this.name = 'dog';
    }
    Pet.prototype.getName = function () {
        return this.name;
    };
    return Pet;
}());
```
Here is how class looks like in ES5 - we’ve create function with property `name` equals `dog`. We used `this` notation to refer to object we going to create. In case when we want to create method we could put it as property to object, but would be much better to add the method to the prototype of our function and we actually did it. It allows us to use `getName` function like it right inside the object and Inheritance and the Prototype chain helps us here:

```javascript
const pet = new Pet();
const pet2 = new Pet();

console.log(Pet.prototype.getName === pet.getName); // true

console.log(pet.getName === pet2.getName); // true
```
As you can see we can get access to the `getName` method right from instance of the our `Pet` class. One more important thing is that method created only once. Even if we create 1000 instances of the `Pet` class this function will be reused in every instance.

The class syntax is simple and it also put all method to prototype automatically. We don’t need to think about as before. But together with classes in ES6 we got arrow functions, the new way how to define and work with classes:

```javascript
const getDate = () => new Date()
```
The syntax of arrow functions is cleaner and shorter. They also have different behavior on execution level - they have bound context from definition scope instead of execution scope in default function, which prevents developers from making a common mistake by passing a function as an argument to another method or function, which could lose the context.

With the advent of the popularity of arrow functions, they began to be used everywhere and even as class methods. Let’s add new method to our class:

```javascript
class Pet {
  name = 'dog';

  getName() {
    return this.name;
  }

  getNameArrow = () => this.name;
}
```
We’ve defined the `getNameArrow` arrow function. It’s do completely the same thing and looks even better and cleaner by the way. But what could be wrong here?

First thing you might noticed we use `=` sign to define a method, which actually means we were define a property. Even VScode highlighted it for us:

![Vscode highlighted method as a property](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2fag5rhnyv8cxh0t1ewm.png)
As we remember in ES5 vs ES6 syntax - all properties will be added right to the class instance instead of prototype. Let’s try to proof it. We can pass our code of class via Babel or TypeScript compiler, even online version, and see result:

```javascript
"use strict";
var Pet = /** @class */ (function () {
    function Pet() {
        this.name = 'dog';
        this.getNameArrow = function () { return this.name; };
    }
    Pet.prototype.getName = function () {
        return this.name;
    };
    return Pet;
}());
```
Here we can notice our methods defined with different ways. The getName method still placed in prototype, but getNameArrow has defined as property inside of object and it will be created for every single instance. Let’s check it in real case:

```javascript
const pet = new Pet();
const pet2 = new Pet();

console.log(pet.getNameArrow === pet2.getNameArrow); // false
```
Every time when we create new instance, we create new function `getNameArrow` as well. Just imagine the case when we need 1000 instances of our Pet with 20 methods inside created as arrow function. It means will be created 20000 useless functions. And this is just when we use arrow functions for that. 

This is actually root cause why we should avoid using arrow functions in classes, or at least think and understand when we can do it. If you know different cases or disagree with that, please put your thoughts to comments.