DEV Community

Chintan Soni
Chintan Soni

Posted on

Arrow Functions vs. Regular Functions in JavaScript: A Comprehensive Guide

In the realm of JavaScript, two primary types of functions reign supreme: arrow functions and regular functions. While both serve the purpose of encapsulating reusable code blocks, they exhibit distinct characteristics that influence their usage and impact on the overall programming flow. Understanding these differences is crucial for JavaScript developers to make informed decisions and craft efficient, maintainable code.

Arrow Function Syntax: A Concise Approach

Arrow functions, also known as lambda expressions, are a concise and expressive way to define functions in JavaScript. Introduced in ES6 (ECMAScript 2015), they offer a shorter and more elegant syntax compared to regular functions.

// Regular function
function square(x) {
  return x * x;
}

// Arrow function
const square = (x) => x * x;
Enter fullscreen mode Exit fullscreen mode

Regular Function Syntax: The Traditional Way

Regular functions, the classic approach to defining functions in JavaScript, have been around since the language's inception. They employ a more explicit syntax, encompassing the function keyword, parameters, and a block of code enclosed in curly braces.

function square(x) {
  return x * x;
}
Enter fullscreen mode Exit fullscreen mode

Key Differences: Unveiling the Distinctions

Beyond their syntactical differences, arrow functions and regular functions diverge in several aspects, each with its own implications for code structure and behavior.

  1. this Binding: Regular functions have their own this binding, which refers to the execution context of the function. This value can change depending on how the function is invoked. Arrow functions, on the other hand, inherit their this binding from the surrounding scope, ensuring consistent behaviour regardless of invocation.

  2. Arguments Object: Regular functions have access to an arguments object, an array-like collection of the function's arguments. Arrow functions do not have this object directly available, but they can still access arguments using the rest parameter syntax (e.g., (...args) => {...}).

  3. Constructor Usage: Regular functions can be used as constructors to create new objects. Arrow functions, however, are not constructors and cannot be invoked with the new keyword. This distinction stems from their different this binding behavior.

  4. Conciseness and Readability: Arrow functions often lead to more concise and readable code, especially for simple functions. Their shorter syntax reduces boilerplate and improves code readability. However, for more complex functions with multiple statements, regular functions may provide better clarity.

Choosing the Right Tool for the Job

The decision between using an arrow function or a regular function depends on the specific context and requirements of the code. Arrow functions are well-suited for short, concise functions, especially within callbacks or nested functions. Regular functions, with their explicit syntax and constructor capabilities, remain valuable for more complex scenarios.

In summary, understanding the differences between arrow functions and regular functions empowers JavaScript developers to make informed choices, enhancing the maintainability and efficiency of their code. By carefully considering the syntax, this binding, arguments access, constructor usage, and conciseness trade-offs, developers can select the most appropriate function type for each task, ensuring clear, well-structured code that aligns with the specific needs of the project.

Top comments (7)

Collapse
 
lebbe profile image
Lars-Erik Bruce • Edited

A thing you forgot to mention: If you use breakpoints in your browser developer tools, and have defined all your functions as arrow functions, the stack trace will just be a path of "anonymous". While if you use regular, decently named, functions, your call stack is actually readable!

Browsers has become better at using the "const" name for the arrow function in the stack trace on error objects. But this has not yet been implemented in the call stack when paused in developer tools. Which makes it pretty obvious that you should write named regular functions most of the time.

Collapse
 
ichintansoni profile image
Chintan Soni

Ohh, I didn't notice that. Thanks for sharing!

Collapse
 
citronbrick profile image
CitronBrick

That is very useful to know.
Thank you.

Collapse
 
lebbe profile image
Lars-Erik Bruce • Edited

Arrow functions often lead to more concise and readable code, especially for simple functions.

This is simply not true, unless we are talking about very specific scenarios. Regular functions are much more concise and straightforward in regular cases:

function aFunction(arg1, arg2) {
  // function body
}

const aFunction = (arg1, arg2) => {
  // function body
}

Enter fullscreen mode Exit fullscreen mode

As you can see, the arrow function, with prettier formatting, takes 3 more characters than a regular function, and is slightly less readable. It gets worse for higher order functions:

function aHigerOrderFunction(arg1, arg2) {
  return function aFunction(arg3, arg4) {
    // function body
  }
}

const aHigerOrderFunction = (arg1, arg2) => (arg3, arg4) => {
  // function body
}

const aHigerOrderFunction = (arg1, arg2) => {
  return (arg3, arg4) => {
    // function body
  }
}
Enter fullscreen mode Exit fullscreen mode

As you can see, the regular function who returns a regular function is pretty straight forward for the brain to parse. While an arrow function returning an arrow function starts to become cumbersome. All code here formatted with prettier as well.

It only gets worse when modern web-hipster starts defining React components in TypeScript, then all hell breaks loose!

const Widget: React.FC<WidgetProps> = ({ title }) => {
  return (
    <div>
      <h1>{title}</h1>
      {/* Render other parts of the component here */}
    </div>
  );
};

export default Widget;

Enter fullscreen mode Exit fullscreen mode
export default function Widget({ title }: WidgetProps) {
  return (
    <div>
      <h1>{title}</h1>
      {/* Render other parts of the component here */}
    </div>
  );
}

Enter fullscreen mode Exit fullscreen mode

That developers actually prefer the first example here, an explicitly typed arrow function, above the much simpler to read regular function(al) component, is beyond me. I have simply no clue why anyone would start doing that. None-the-less I see that way of writing components everywhere. In my honest opinion, this is a sickness that needs a cure.

The regular function component is very straight forward to read, and TypeScript manages to deduce its types all by itself. And we as developers know that it is a Component, so we don't need that React.FC type either.

Collapse
 
ichintansoni profile image
Chintan Soni

May be I am caught with the same sickness, you're talking about. But yes, now I see where you coming from, I agree with your standpoint. Thanks for the explanation!

Collapse
 
lebbe profile image
Lars-Erik Bruce

We must not forget where arrow functions shine, though. When we need those cute small lambdas to perform mapping and sorting and the likes :)

  numbers
  .map((n) => parseInt(n, 10))
  .sort((a, b) => a - b);
Enter fullscreen mode Exit fullscreen mode
  numbers
    .map(function (n) {
      return parseInt(n, 10);
    })
    .sort(function (a, b) {
      return a - b;
    });
Enter fullscreen mode Exit fullscreen mode

In cases like this, arrow functions truly shine! Unfortunately the first example isn't formatted with prettier, beccause prettier in this instance actually makes the code less readable again:

numbers.map((n) => parseInt(n, 10)).sort((a, b) => a - b);
Enter fullscreen mode Exit fullscreen mode

I really don't know why prettier insist to place all this on the same line, its just cumbersome and a bother to read.

Collapse
 
citronbrick profile image
CitronBrick

I use the function keyword while creating general functions.
I reserve the Arrow syntax for callback arguments &
especially for event listener methods, in order to preserve the value of this.
The event listener methods are usually a 'gotcha' in React.