Sitemap

3 Reasons not to use Arrow Functions

Why do you prefer arrow functions over normal function?

4 min readJul 12, 2025

--

Press enter or click to view image in full size
Photo by Luca Bravo on Unsplash

While arrow functions bring conciseness to JavaScript, they also introduce a few “curses” that can trip up developers, especially when debugging or maintaining code. Let’s explore these drawbacks with relevant examples.

The Three Curses of Arrow Functions

Curse 1: The “Read Whole Function Body” Curse 🕵️‍♀️

Arrow functions, particularly implicit returns, can make it challenging to immediately grasp what a function does without reading its entire body.

When an arrow function is concise, this isn’t a problem. But for more complex one-liners or functions that are chained, it can lead to confusion.

Explanation: With traditional function declarations or expressions, the function keyword immediately signals that a block of code is about to define a self-contained operation.

Arrow functions, especially those with implicit returns, blend more seamlessly into the surrounding code, sometimes making their boundaries and purpose less obvious at first glance. You have to scan the entire expression to understand what's being returned.

Code Example:

// Traditional function - clearly defines a block of logic
// Function name clearly shows what this function will do
function calculateTotal(items) {
let total = 0;
items.forEach(item => {
total += item.price * item.quantity;
});
return total;
}
// Arrow function with implicit return - requires reading the whole line to understand
const getActiveUserEmails = (users) =>
users.filter((user) => user.isActive).map((user) => user.email);
// What if it's more complex?

const processData = (data) =>
data
.filter((item) => item.status === "active" && item.value > 100)
.sort((a, b) => b.timestamp - a.timestamp)
.map((item) => ({ id: item.id, processedAt: new Date() }));
// To understand 'processData', you must read through the entire chain of methods
// and the final object literal to know what it's ultimately doing and returning.

Curse 2: The “Anonymous in Stack Trace” Curse 👻

When an error occurs within an anonymous arrow function, debugging can become a headache because the function won’t have a descriptive name in the call stack. This means tracing the origin of an error back through your code can be much harder.

Explanation: Named functions provide valuable context in stack traces, showing you exactly which function was executing when an error occurred. Anonymous arrow functions, by their nature, don’t have this name. In a stack trace, they might simply appear as <anonymous> or some generic internal reference, obscuring the path of execution.

Code Example:

JavaScript

// util.js
function perform(cb) {cb()};

perform((item) => {
if (!item.value) {
throw new Error("Item must have a value"); // This error originates from an anonymous arrow function
}
return item.value * 2;
});
Press enter or click to view image in full size
with arrow function as callback

Now let’s pass a named function.

function perform(cb) {cb()};

perform(function transform(item){
if (!item.value) {
throw new Error("Item must have a value"); // This error originates from an anonymous arrow function
}
return item.value * 2;
});
Press enter or click to view image in full size
with same anyonymous function, but this time with function

Now you can argue that we can create an arrow function and assign it to a const show that name show up in stack trace.

Well if you can do this, go ahead, but does people really have time? the answer is probably NO.

Arrow functions are the worst contender for callback functions.

Curse 3: Affects Readability, Especially in JSX/TSX 🎨

While often praised for conciseness in JSX/TSX, arrow functions can sometimes make the code harder to read, especially when they involve complex logic or multiple arguments passed directly within component props.

Explanation: In React/JSX, it’s common to pass inline arrow functions as props for event handlers (onClick, onChange). When these functions become complex, they can bloat the JSX, making it less declarative and harder to parse visually. This intermingling of logic directly within the UI structure can obscure both the component's rendering logic and the handler's behavior.

Code Example (React/JSX):

JavaScript

// Less readable due to inline complex arrow function
function UserList({ users, filter }) {
return (
<div>
{users
.filter((user) => user.isActive && user.role === filter)
.map((user) => (
<div
key={user.id}
onClick={() => { // Complex inline arrow function
if (user.status === 'active') {
console.log(`Activating user: ${user.name}`);
// Imagine more complex logic here, like dispatching an action or making an API call
} else {
alert(`Cannot activate inactive user: ${user.name}`);
}
}}
>
{user.name}
</div>
))}
</div>
);
}
// More readable approach: Extract the function


function UserListClean({ users, filter }) {
const handleUserClick = (user) => {
if (user.status === 'active') {
console.log(`Activating user: ${user.name}`);
// Complex logic is now encapsulated
} else {
alert(`Cannot activate inactive user: ${user.name}`);
}
};
return (
<div>
{users
.filter((user) => user.isActive && user.role === filter)
.map((user) => (
<div key={user.id} onClick={() => handleUserClick(user)}>
{user.name}
</div>
))}
</div>
);
}

In the less readable example, the inline onClick handler makes the JSX visually dense and difficult to scan. Extracting the function (as in UserListClean) improves readability by separating concerns and keeping the JSX focused on structure.

When to use arrow function?

When you want to write this aware code. (Preserve binding of this across different function call), In Class

other than this, I don’t see any use case of arrow function, other than it’s cool syntax.

Do let me know your thoughts about it.

.

Tags for SEO:
#frontend #javascript #html #frontendmaster

--

--

Frontend Master
Frontend Master

Written by Frontend Master

A decade-long dance with code, sculpting the digital landscape. https://topmate.io/frontendmaster

Responses (4)