DEV Community

Cover image for Understanding Arrow Functions: Syntax, Features, and Use Cases
Hyemiie
Hyemiie

Posted on

Understanding Arrow Functions: Syntax, Features, and Use Cases

  1. Introduction
  2. Features of an arrow function
  3. Syntax Variations for Declaring Arrow Functions

  4. Arrow function and "this" keyword??

  5. Other features of arrow functions

Introduction
Functions are a fundamental part of JavaScript as they enable developers to break down complex tasks into smaller, manageable units. There are two major syntaxes used to define functions in JavaScript. These are the regular function syntax and the arrow function syntax.

The regular function has been a part of JavaScript since its inception. However, the arrow function was introduced in ECMAScript 2015 (ES6) and provides a more concise way to define functions compared to regular function expressions. It also has some features that makes it different from regular functions.

In this article, we will talk about how arrow functions work, including their advantages and use cases. We would also discuss the syntax variations in arrow functions and how they work with bindings in JavaScript.

Features of an arrow function
When declaring a function with the regular function syntax, you would have;

function addition(num1, num2){
    sum = num1+num2;
    return sum
   }
Enter fullscreen mode Exit fullscreen mode

Using the arrow syntax, the function can be written as;

const addition = (num1 , num2) => {
    sum = num1 +  num2
     return sum
    }

Enter fullscreen mode Exit fullscreen mode

From this example, we can point out some key features of arrow functions.

  1. const declaration: Instead of using the function keyword, we used the const keyword to declare the arrow function. This ensures that the function reference cannot be reassigned.
    You can also use the var or let keyword depending on your specific use case.

  2. Parameters: Just like in regular functions, the parameters in arrow functions are declared within parentheses (). In this example, num1 and num2 are the parameters specified within parentheses (num1, num2).

  3. Arrow (=>) notation: The arrow notation separates the parameter list from the function body. It uses the equal sign (=) followed by a greater than sign (>), which forms an arrow. The arrow notation shows that the parameters are used to define the function.

  4. Function Body: The function body contains the code that is executed when the function is called. It is enclosed in curly braces {}. For example, in the code, the function body calculates the sum of num1 and num2 and returns the result using the return statement.

const addition = (num1 , num2) => {
    sum = num1 +  num2
     return sum
    }

Enter fullscreen mode Exit fullscreen mode

If the function body only has a return statement, you can even have a shorter function expression.

const addition = (num1 , num2 ) => {num1 +  num2}

Enter fullscreen mode Exit fullscreen mode

This is known as Implicit Return. It means that the value of the expression is automatically returned without using the return keyword

Syntax Variations for Declaring Arrow Functions

Arrow functions can be defined using different syntax. This depends on the type of function and the context in which it is being used. Here are some examples.

Arrow functions with parameters:
Just like in the previous code snippet, you can declare an arrow function with parameters

const addition = (num1 , num2 ) => {
    const sum = num1 +  num2
     return sum
   }
Enter fullscreen mode Exit fullscreen mode

If the function has only one parameter, you can omit the parentheses. For example,

const displayNum = num1  => {
    const Num= num1
     return Num
   }
Enter fullscreen mode Exit fullscreen mode

Arrow functions with default parameters:
Default parameters allow you to assign default values to function parameters in case no argument is passed when invoking the function.
Arrow functions support default parameters in the same way as regular functions. For example;


const multiply = (a, b= 1) => {
    return a * b;
  };

  console.log(multiply(5));
  console.log(multiply(5, 2))
Enter fullscreen mode Exit fullscreen mode

In the preceding code, we created a function “multiply” which takes two parameters, a and b, with b having a default value of 1.
This means that if the value of b is not provided, then the function executes as 5*1. However, if a value is provided for b, for instance, 2, it uses the provided value. This would execute as 5*2.

Declaring arrow functions without parameters:
If a function doesn't take any parameter, then you can use empty parentheses.

const greeting = () => {
     console.log('Hello World');  
}
greeting();
Enter fullscreen mode Exit fullscreen mode

Arrow Function as Expressions
You can also create an arrow function and use it as an expression. For example,

let score = 83;

let remark= (score < 50) ?
  () => console.log('pass') :
  () => console.log('Fail');

remark();
Enter fullscreen mode Exit fullscreen mode

This may be a bit confusing so let’s break down the code;

  • In Line 1 we declare a variable named score and assign it a value of 83. This variable represents the score that we are passing to the function

  • In Lines 2-5 we use a ternary operator to assign a value to the remark variable.
    The ternary operator checks if the score is less than 50. If the condition is met, it assigns an arrow function () => console.log("Pass") to the remark variable. Otherwise, it assigns an arrow function () => console.log("Fail") to remark.

Finally, we call the remark function, which will execute based on the value of the score. In this case, since the score is 83 (which is greater than 50), it will log 'pass' to the console.

Arrow Function and "this" Keyword.

In regular functions, the value of a "this" variable is determined by how the function is called or the object it is called upon. This is because regular functions have their own "this" binding and can change depending on the context in which it is invoked. For example

Regular function

const student = {
  name: 'Grace',
  age: 12,
  year: 2,
  studentProfile: function() {
    return 'Hi, my name is ' + this.name + ' and I am in year ' + this.year + '.';
  }
};

student.studentProfile();
Enter fullscreen mode Exit fullscreen mode

In the code snippet, we defined an object named ‘student’ with properties name, age, and year. It also has an inner function called studentProfile.
The _studentProfile _is defined using the regular function syntax. Hence, it uses the “this” keyword to refer to the object it is called upon which is the student object in this case. The output would therefore be

Hi, my name is Grace and I am in year 2

However, in arrow functions, the ‘this’ keyword inherits its value from the surrounding (lexical) scope in which they are defined rather than how it is called. This means that the value of ‘this’ can change depending on the context in which the function is executed. For instance

Arrow function

const student = {
    name: 'Grace',
    age: 12,
    year: 2,
    studentProfile: () => {
      return `Hi, my name is ${this.name} and I am in year ${this.year}.`;
    }
  };

    student.studentProfile();
Enter fullscreen mode Exit fullscreen mode

As we mentioned, arrow functions do not have their own ‘this’ context. Instead, they inherit the "this" value from the surrounding scope, which is the global scope in this case. Therefore, this.name and this.year within the arrow function does not refer to the properties of the student object. Instead, they reference properties of the global object (for example, a window in a browser environment).
As a result, when executing this code snippet, the output would be;

Hi, my name is undefined and I am in year undefined.

To correctly use the "this" keyword in this scenario, we would use a regular function instead of an arrow function.

const student = {
  name: 'Grace',
  age: 12,
  year: 2,
  studentProfile: function() {
    setTimeout(() => {
      console.log(Hi, my name is ${this.name} and I am in year ${this.year}.);
    }, 1000);
  }
};

student.studentProfile();
Enter fullscreen mode Exit fullscreen mode

In this example, the studentProfile function is defined as a regular function and we used a global object, setTimeout() with an arrow function as the callback. Therefore, the arrow function would inherit the "this" value from the surrounding studentProfile function. This would now correctly log :

Hi, my name is Grace and I am in year 2

Other features of Arrow functions.

Although arrow functions provide many benefits, they also have some features which could be considered limitations. These features could affect the way your function executes, so it's important to be aware of them before making use of arrow functions.

  • Calling arrow functions with the new keyword throws a TypeError. They also don't have access to the new.target keyword. Therefore they cannot be used as constructors.

  • Arrow functions do not have bindings to this, arguments, or super keywords. Hence, they do not work with object methods that require access to the object's properties through these keywords.

  • Arrow cannot be used to call parent class methods as they do not have access to the _super _keyword which is used for this purpose.

  • Arrow functions don't support the use of yield keyword within their body therefore they cannot be directly created as generator functions.

Conclusion
Arrow functions are especially useful for creating concise function expressions. However, it's best to use regular functions or other constructs when working with features that are not compatible with arrow functions. By understanding and applying the strengths and limitations of arrow functions, you can make choices that would help improve your code's functionality.

Top comments (0)