Understanding the Difference Between Arrow Functions and Regular Functions in JavaScript

Understanding the Difference Between Arrow Functions and Regular Functions in JavaScript

Two common types of functions in JavaScript are arrow functions and regular functions.

Home / Blog / HTML, CSS, JavaScript / Understanding the Difference Between Arrow Functions and Regular Functions in JavaScript

JavaScript, a versatile programming language, offers multiple ways to define and use functions. Two common types of functions in JavaScript are arrow functions and regular functions. Although they may appear similar at first glance, there exist vital differences between the two in terms of syntax, behavior, and use cases.

Syntax

Arrow functions have a more concise syntax compared to regular functions. Denoted by the ‘=>‘ arrow symbol, arrow functions eliminate the need for the function keyword and often allow for implicit return statements for single expressions. Consider the following example of an arrow function that doubles a given number:

const double = (num) => num * 2;
console.log( double(5) );
// prints: 10

On the other hand, regular functions are defined using the function keyword, followed by the function name, parameters within parentheses, and a block of code wrapped in curly braces. Explicit return statements are used to return values. Here’s the equivalent regular function for the previous example:

function double(num) {
    return num * 2;
}
console.log( double(5) );

Binding of ‘this’

The binding of the ‘this‘ keyword constitutes another significant difference between arrow functions and regular functions. In regular functions, the value of ‘this‘ is determined by how the function is invoked and can vary depending on the context. For instance, when a regular function is used as a method of an object, ‘this‘ refers to the object itself. However, when the same function is called without any context, ‘this’ usually refers to the global object (e.g., window in browsers, global in Node.js).

Arrow functions, however, do not bind their own ‘this‘ value. Instead, they inherit the ‘this‘ value from the surrounding scope or the linguistic context in which they are defined. This behavior proves advantageous when working with nested functions or callbacks, as the ‘this‘ value inside an arrow function remains the same as the outer scope, irrespective of how it is invoked.

const object = {
    name: "Projects Engine",

    regularFunc: function() {
        console.log(this.name); // 'Projects Engine'
        
        setTimeout(function() {
        console.log(this.name); // undefined (or the global object in non-strict mode)
        }, 1000);
    },

    arrowFunc: function() {
        console.log(this.name); // 'Projects Engine'

        setTimeout(() => {
        console.log(this.name); // 'Projects Engine'
        }, 1000);
    }
};
    
object.regularFunc();
object.arrowFunc();     

Arguments object

Regular functions have access to the ‘arguments‘ object, an array-like object containing the arguments passed to the function. This object proves useful when the number of arguments is not known in advance. However, arrow functions do not possess their own ‘arguments‘ object. Instead, they inherit the ‘arguments‘ object from the enclosing scope.

function regularFunc(a, b) {
    console.log(arguments[0]); // Output: 1
    console.log(arguments[1]); // Output: 2
    console.log(arguments.length); // Output: 2
}
    
const arrowFunc = (a, b) => {
    console.log(arguments[0]); // ƒ (e,t){return new ce.fn.init(e,t)}
    console.log(arguments[1]); // undefined
    console.log(arguments.length); // 1
}
    
regularFunc(1, 2);
arrowFunc(1, 2);


Certainly! Here’s a different example that demonstrates the difference in behavior related to the ‘arguments’ object:

function regularFunc(a, b) {
  console.log(arguments[0]); // Output: 1
  console.log(arguments[1]); // Output: 2
  console.log(arguments.length); // Output: 2
}

const arrowFunc = (a, b) => {
  console.log(arguments[0]); // ReferenceError: arguments is not defined
  console.log(arguments[1]); // ReferenceError: arguments is not defined
  console.log(arguments.length); // ReferenceError: arguments is not defined
}

regularFunc(1, 2);
arrowFunc(1, 2);

In the regular function regularFunc, we can access the individual arguments using the arguments object. In this example, we pass 1 as the first argument and 2 as the second argument. By accessing arguments[0], we can retrieve the value of the first argument (1), and similarly, arguments[1] returns the value of the second argument (2). The arguments.length property returns the number of arguments passed to the function, which in this case is 2.

However, in the arrow function arrowFunc, attempting to access the arguments object directly results in a ReferenceError. Arrow functions do not have their own arguments object. Instead, they inherit the arguments object from the enclosing scope. In this case, since the arrow function is defined within a block scope that does not have an arguments object, trying to access it throws an error.

It’s important to note that when using arrow functions if you need access to the arguments passed to the function, you can use the rest parameter syntax (...args) to gather all the arguments into an array-like object:

const arrowFunc = (...args) => {
  console.log(args[0]); // Output: 1
  console.log(args[1]); // Output: 2
  console.log(args.length); // Output: 2
}

arrowFunc(1, 2);

In this modified example, the rest parameter ...args collects all the arguments passed to the arrow function and stores them in an array-like object args. Now, we can access the individual arguments using array notation (args[0], args[1]), and args.length provides the length of the arguments array, which is 2 in this case.

Use Cases

Arrow functions find common usage in scenarios where the shorter and more concise syntax is desired, particularly for simple functions. They are often employed with array methods like map, filter, and reduce, where brevity is favored.

Regular functions, on the other hand, remain the preferred choice in many cases, especially when the flexibility of ‘this’ binding or the ‘arguments’ object is required. They work well for defining methods within objects or when working with constructor functions.

In conclusion, both arrow functions and regular functions possess their own strengths and are suited for different situations. Understanding the differences in their syntax, behavior, and use cases is crucial for writing clean and maintainable JavaScript code. By leveraging the appropriate type of function in a suitable context, developers can enhance productivity and ensure their code is readable and efficient.