Understanding Arrow Function Expressions in JavaScript
Tags: javascript, es6, functions, arrowfunctions
Published: 2023-02-05 15:39:17

According to recent developer surveys, JavaScript is still the most commonly-used programming language in the world and it remains in high demand by various organizations across the globe. In light of that piece of information coupled with the fact that I love writing about JavaScript, I'll be dedicating more time and resources to write up quality content about the language. The topic with which we are now concerned is; **_Arrow Functions_**. Without wasting any more time, let's start looking at the ins and outs of Arrow Functions. But before we do that, I'll like us to have a little refresher on regular or traditional JS functions so that it puts everything into perspective. Shall we?

[Functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions) are one of the fundamental building blocks in JavaScript and they are basically blocks of code designed to perform particular tasks. To use a function, you must first define it somewhere in the scope from which you wish to call it.

Functions are defined, or declared, with the `function` keyword. Below is the syntax for a function in JavaScript.

```javascript
function nameOfFunction() {
    // Block of code to be executed
}
```
The declaration begins with the `function` keyword, followed by the name of the function. Function declarations load into the execution context before any code runs. This is known as [hoisting](https://developer.mozilla.org/en-US/docs/Glossary/Hoisting), meaning you can use the function before you declare it.

Another way of defining a function is by means of a function expression which is basically assigning a function to a variable. Unlike a function declaration, function expressions are not pre-loaded into the execution context, and only run when the program encounters it. Below is an example of a function expression that computes the sum of two numbers.

```javascript
const sum = function (a, b) {
  return a + b
}
```
Trying to call this function before defining it will result in an error. Now unto arrow functions!
## Arrow functions
An arrow function is fundamentally a shorter alternative to traditional JS function expressions with a few semantic differences and a deliberate limitation in their usage. Arrow functions are always anonymous—there is no way to name an arrow function. In the next section, you will explore the syntactical and practical differences between arrow functions and traditional JavaScript functions.
### Behavior and Syntax of Arrow Functions
Arrow functions have a few important distinctions in how they work that make them different from traditional JS functions, as well as a few syntactic enhancements. These differences are:

- Arrow functions don't have their own bindings to [this](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this)
- Arrow Functions Have No `constructor` or `prototype`.

Now let us look at what these points mean in detail.

**Arrow functions don't have their own bindings to `this`:** The context inside arrow functions is lexically or statically defined. What this means is that, unlike regular JS functions, the value of `this` inside arrow functions is not dependent on how they are called or how they are defined. It depends only on its enclosing context. This might seem a little bit confusing so let's try to understand it by looking at an example. In this example, we will create a basic object and see the use of the object in Javascript

```javascript
let Student = function(student, age) {
        this.student = student;
        this.age = age;
        this.info = function() {

         // logs Student
         console.log(this);

         setTimeout(function() {
            // here this!=Student
           console.log(this.student + " is " + this.age + 
                                              " years old");
          }, 2000);
        }
    } 
 let student1 = new Student('James', 19);

    // logs : undefined is undefined years old after 3 seconds
    student1.info();
```
The reason that we get `undefined` values outputted instead of the proper info is because the `function()` defined as the callback for [setTimeout()](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout) is a traditional JS function and this means that its context is set to the global context or in other words the value of `this` is set to the [window](https://developer.mozilla.org/en-US/docs/Web/API/Window) object.
This happens because every regular JavaScript function defines its own this or context depending on their invocation. The context of the enclosing objects or function does not affect this tendency to automatically define their own context.

Now how do we solve this issue? One obvious solution that might come to mind is, what if the function did not define its own this or context? What if it inherited the context from `info()`, because that would mean the callback function gets the this as was defined in `info()`
Well, that is exactly what arrow functions do. They retain the value of `this` from their enclosing context. In the above example, if the callback function in setTimeout() were an arrow function it would inherit the value of `this` from its enclosing context – `info()`

```javascript
let Student = function(student, age) {
        this.student = student;
        this.age = age;
        this.info = function() {

            // logs Student
            console.log(this); 

           setTimeout(() => { 
            // arrow function to make lexical "this" binding
            // here this=Student."this" has been inherited
            console.log(this.student + " is " + this.age 
                                           + " years old");
           }, 2000);
        }
    } 
    let student1 = new Student('James', 19);

    // logs : James is 19 years old after 2 seconds
    student1.info();
```
An arrow function’s `this` value is the same as the value of `this` in its enclosing context that is the context immediately outside it. If used outside any enclosing function, an arrow function inherits the global context, thereby setting the value of `this` to the global window object.

**Arrow Functions Have No `constructor` or `prototype`:** In JavaScript, functions and classes have a `prototype` property, which is what it uses as a blueprint for cloning and [inheritance](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain). To demonstrate this, create a function and log the automatically assigned `prototype` property to the console:

```javascript
function myFunction() {
  this.number = 8
}

// Log the prototype property of myFunction
console.log(myFunction.prototype)
```
This will print the following to the console:

```javascript
Output
{constructor: ƒ}
```
This shows that in the `prototype` property there is an object with a `constructor`. This allows you to use the `new` keyword to create an instance of the function:
```javascript
const newInstance = new myFunction()

console.log(newInstance.value)
```
This will give the value of the `number` property that you defined when you first declared the function. In contrast, arrow functions do not have a `prototype` property. Create an arrow function and try to log its `prototype` to the console, you'll see that the output you get is `undefined` . As a result of the missing `prototype` property, the `new` keyword is not available and you cannot construct an instance of the arrow function.

In addition to these differences that arrow functions exhibit, there are a few optional syntactic changes that make writing arrow functions quicker and less verbose. The next section will show examples of these syntax changes.

### Arrow Function Implicit Return
It is common knowledge that the body of a traditional JavaScript function is contained within a block using curly brackets `{}` and ends when the code encounters a `return` keyword. The following is what this implementation looks like as an arrow function:

```javascript 
const sum = (x, y) => {
  return x + y
}
```
Arrow functions also allow for an omission of the `return` keyword and curly brackets altogether. When this happens, there is an implicit return.
```javascript
const sum = (a, b) => a + b
```

Implicit return is useful for creating succinct one-line operations in array methods such as `map` , `filter` and other common array methods. Note that both the brackets and the `return` keyword must be omitted. If you cannot write the body as a one-line return statement, then you will have to use the normal block body syntax.

In a case where an object is returned, the syntax requires that you wrap the object literal in parentheses as shown in the example below:

```javascript
const sum = (a, b) => ({result: a + b})

sum(7, 2)
```
If you don't enclose the object literal in parentheses, the brackets will be treated as a function body and will not compute a return value.

> **Note:** If your Arrow function has no arguments you should not leave out the parentheses because they are required.

### Conclusion
Always try to remember the differences between regular JS functions and Arrow functions. As we have just seen, they might behave differently in the same situations. It is good practice to use arrow functions for [callbacks](https://developer.mozilla.org/en-US/docs/Glossary/Callback_function) and [closures](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures) because their syntax is concise and cleaner.