DEV Community

AlexErdei73
AlexErdei73

Posted on

Arrow functions in JavaScript

In this article, I explain everything that a JavaScript developer should know about arrow functions. I am going to reveal the main differences between regular and arrow functions. I am going to deal with some marginal cases when the two different function syntax is not interchangeable. You may be surprised that there are situations like this even in very practical JavaScript. If this was new to you, it is well worth keeping on reading and even better to try my code samples.

The history of arrow functions

Arrow functions got into the language in 2015, when the ES6 specification was introduced in the language. This feature brought one of the most significant changes regarding how modern JavaScript code looks compared to the older ES5 standard, which was introduced in 2010. Have you known why these were actually introduced in the language? It was mainly because of a simple event-handling problem in one of the leading front-end JavaScript libraries, React.

React is a library, which solves the user interface problem in its unique way. It helps developers get rid of a lot of DOM manipulation code, which was usually written in jQuery or in vanilla JavaScript. This part of the code was huge for a large user interface and error-prone. This kind of code usually re-rendered most of the visual elements whenever any interactivity changed the state (the data visualised) of the user interface. The change in the state is usually small enough not to render all the elements over and over again, but the code was complex even without dealing with such details.

React solves this problem very nicely but this solution, which was relatively new in 2015, brought new problems to solve. React used class components at that time. These describe visual components with ES6 classes. Before 2015 React had its own class system for its components. This syntax is used in vanilla JavaScript to write code according to the Object Oriented Paradigm (OOP). At that time this syntax was the only available one for stateful visual components, which have their own state (data) to show in the browser. In OOP the same class can generate more instances of the same visual component. These usually differ regarding their state, but the code exists only in one class for all component instances. This is great for code reuse. If all, I am writing about here, were new to you, please watch the following video about React.

The above video points out a well-known problem with event handling in React. This is explained at 01h01min11s in the video. You can add your event handler function to the component as a method. When you call that function as a method of the component, you can use the 'this' keyword in the function to reach the data of the component. The value of the 'this' keyword in JavaScript is called the function context or shortly just context. On the other hand, if you call the function as a stand-alone function, the value of this is 'undefined' in strict mode. This is the situation when you pass your event handler to React. As the video shows arrow functions are the easiest solution for this problem. If we define the method as an arrow function instead of a regular function, the value of 'this' cannot be changed any more. Regardless of how the function is called, 'this' always points to the component instance, which defines the arrow function. This solves the above problem in the simplest possible way.

The main reason to put arrow functions in the JavaScript language might have been to give a simple solution for marginal problems like this regarding function context. Constructs similar to arrow functions have been known since Lisp (1958). These are not new concepts, but they got back to the languages, which are widespread today, with JavaScript. Since 2015 these have become widespread in other languages too. In JavaScript the usage of these is not always justified, hence we need to know about them in detail.

The syntax of arrow functions

Arrow functions are anonymous function expressions. Let us see the following example.

// regular function
function handleClick() {
  // ... 
};
Enter fullscreen mode Exit fullscreen mode

The equivalent function expression is the following.

// function expression
const handleClick = function() {
  // ...
};
Enter fullscreen mode Exit fullscreen mode

The syntax of the arrow function is below.

// arrow function
const handleClick = () => {
  // ...
};
Enter fullscreen mode Exit fullscreen mode

The simple syntax can remind us of functions in mathematics. There, functions are usually maps, which map numbers to numbers. In the case of JavaScript, the input parameters can be written between the curly braces similarly to regular functions. The output can be given back with the return keyword or with the implicit return if there was any.

Key differences between arrow functions and regular functions

  1. Arrow functions need to be defined before usage. Unlike regular functions, arrow functions cannot be used in the code before their definition. Regarding this these behave like regular function expressions. We shortly can say the hoisting is different.

  2. Arrow functions are always anonymous function expressions. It simply means that there is no name associated with them in their defining expression.

  3. The context of arrow functions is inherited from the closure where these are defined. It cannot change during runtime unlike in the case of a regular function. This is the key difference between arrow functions and regular functions and the main reason for their introduction into the language.

Arrow function example

The React example, what we saw in the video can be reproduced without React in vanilla JavaScript. It shows well the main difference in a simpler context. The example can be cloned from the arrow function example GitHub repository.

The index.html file of the example is the following.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Arrow Function Example</title>
  </head>
  <body>
    <h1>Please Open The Developer Console!</h1>
    <button type="button" id="arrow">Arrow</botton>
    <button type="button" id="function">Function</button>
  </body>
  <script src="index.js"></script>
</html>
Enter fullscreen mode Exit fullscreen mode

The index.js file can be seen below.

class Component {
  constructor() {
    this.someValue = "Instance";
    this.buttonArrow = document.querySelector("#arrow");
    this.buttonArrow.addEventListener("click", this.handleClickArrow);
    this.buttonFunction = document.querySelector("#function");
    //You can bind the value of this to the instance of Component if you uncomment the next line.
    //this.handleClickFunction = this.handleClickFunction.bind(this);
    //When the button is pressed it calls the handleClickFunction, the value of this is the buttonFunction object
    this.buttonFunction.addEventListener("click", this.handleClickFunction);
    //If we don't add someValue to the buttonFunction the code brakes when the button is pressed
    this.buttonFunction.someValue = "Button";
  }

  //In the arrow function the value of this is bound to the actual instance of Component
  //It doesn't matter how handleClickArrow is called
  handleClickArrow = () => {
    console.log("Arrow pressed!");
    console.log("this: ", this);
    console.log("someValue: ", this.someValue);
  };

  //In the regular function the value of this depends how it is called
  handleClickFunction() {
    console.log("Function pressed!");
    console.log("this: ", this);
    console.log("someValue: ", this.someValue);
  }
}

const instance = new Component();
console.log(instance);
instance.handleClickArrow();
//here the value of this is the instance
instance.handleClickFunction();
Enter fullscreen mode Exit fullscreen mode

After cloning the example you should open the index.html file in the browser. You will see a simple component with two buttons. The Function button has a regular function event handler. The event handler of the Arrow button is an arrow function. The main program first creates an instance of the Component class and then calls the event handlers as methods. The value of 'this' in both calls is the instance, so 'someValue' is logged to the console in both cases as 'Instance'. On the other hand, when we press the Function button, the event handler gets the value of 'this' as the 'buttonFunction' instance of the button DOM element. This object holds 'someValue' as 'Button', so it is logged to the console. The arrow function on the other hand behaves the same regardless, of how it is called. When you press the Arrow button, the arrow function event handler logs to the console the 'Instance' word, just like it did when the main program called it.

In JavaScript, functions are objects with methods. Regular functions have the bind method, which can return another function. The function, which is returned, has the value of 'this' bound to the instance in this example. If you remove the comment from the line, which does it in the constructor, both event handlers will behave the same, just like in the video by Mosh.

Arrow functions as class methods

The above example logs the value of the 'instance' variable to the console. It can be seen from the output, that the arrow function method is a method of the instance, unlike the regular function method, which belongs to the prototype object. Both methods can be called on the instance. Using instance methods has a disadvantage because, in the case of a lot of instances, the arrow function method will be defined as many times as many instances exist. The regular function is only defined once in the prototype object. Arrow functions are not recommended as methods for performance reasons, especially if the class has a lot of instances. Some developers may be unaware of this disadvantage, hence I pointed it out here.

Example where arrow functions cannot be used

There can be cases when you use an external library. This library imports a function from you, and then it tries to bind the value of 'this' to some of its objects. In a case like this, you cannot use arrow functions, because the value of 'this' cannot be bound in that case. This might be the situation for the following code in Mongoose, which is used to connect your Express code to MongoDB.

// Virtual for author's URL
AuthorSchema.virtual("url").get(function () {
  // We don't use an arrow function as we'll need the this object
  return `/catalog/author/${this._id}`;
});
Enter fullscreen mode Exit fullscreen mode

This example is part of a Mongoose Schema definition. Mongoose lets you define virtual methods, which return data, which is not directly available from the MongoDB data model, but some transformation of the data. The above sample for example defines the 'url' virtual method, to get the URL of an access point in an Express app on the back end. We cannot pass an arrow function here to the get method, because Mongoose binds the value of 'this' to the actual model instance. This is not possible with an arrow function. More information available about the code sample in the following Mongoose tuorial

Acknowledgement

I would like to say thank The Odin Project to teach me JavaScript. I would also like to say thank those members, whom I had conversations about the topic with. Please check the comment section regarding this after the following article about callbacks

Top comments (0)