Understanding the Difference Between Arrow Functions and Traditional Functions

RIMANSHU SINGHRIMANSHU SINGH
10 min read

Hey everyone! I know we’ve all seen JavaScript functions before — how they work, how we use them, blah blah 😒. But stick with me, because by the end of this, you’ll know a lot more!

We’re going to talk about different types of functions (yep, there are more than one!), the ways to use them, and when to pick a normal function or an arrow one ➡️🧠

So get ready — fasten your seatbelt and put your oxygen mask on, because we’re diving deep into the ocean of functions 🌊💻

Let’s make functions fun {finally}! 😄

Before diving into Arrow or Normal functions, let's revise function declarations (function definitions, function statement), function expressions.

Functions are one of the fundamental building blocks in every programming language, i’m specially talking about JavaScript.

Function Declaration

A function definition (also called a function declaration, or function statement) consists of the function keyword, followed by:

  • The name of the function.

  • A list of parameters to the function, enclosed in parentheses and separated by commas.

  • The JavaScript statements that define the function, enclosed in curly braces, { /* … */ }.

For example, the following code defines a function named square:

function square(number) {
  return number * number;
}

Function Expressions

While the function declaration above is syntactically a statement, functions can also be created by a function expression.

Rule to Identify a Function Expression

  1. When it’s not in the statement position, then it’s function expression

  2. If you see the function keyword being used in a place where the result is being assigned to a variable, passed as an argument, or returned from another function, then it's called a function expression.

    But if the function stands on its own as a separate statement — not assigned or passed around — then it's a function declaration.

    Here’s a quick cheat code to tell them apart:

    If the function is just chilling by itself like

     function sayHi() { ... }
    
     // This is a function declaration. It’s bold. It’s confident. It doesn’t need anyone.☺️
    

    But if the function is getting handed off, assigned, or tucked inside something, like:

     const sayHi = function() { ... }  //assigned to a variable
     arr.map(function (){}) //passed as an argument
     return function (){} //return
     const obj = { m: function (){} } //part of object
    
     // That’s function expression. It’s shy. It needs home (like a variable or a parameter)
    

That's why you get a reference error when you try to run this type of function:

[1].map(function test(n){
    console.log(n);
})
test();
// --------------------------------------------------------------------
//error:
ReferenceError: test is not defined

Such a function can be anonymous; it does not have to have a name. For example, the function square could have been defined as:

const square = function (number) {
  return number * number;
};

console.log(square(4)); // 16

However, a name can be provided with a function expression. Providing a name allows the function to refer to itself, and also makes it easier to identify the function in a debugger's stack traces with some limitations.
Such as:

  • This type of declared function can only be called by its variable name.

      const factorial = function fac(n) {
        return n < 2 ? 1 : n * fac(n - 1);
      };
    
      console.log(factorial(3)); // 6
    
  • As you see in the example above, the function is called by the variable name factorial().

  • The function name fac is only accessible inside the function definition.

  • You cannot call a function defined by a function expression using its function name outside the function definition; you must use its variable name.

Superpower of Traditional function

1st Superpower

Can be used before declaration (this happens because of Hoisting)

test();
function test(){
    console.log("Namste Duniya!");
}

2nd Superpower

The this Keyword: Does it need any introduction? Naam hi kaafi hai😎
Every function has a keyword called this. Let’s console this.
When you call a regular function, the value of this can change depending on how you call it.

  • If you just call the function directly, like this: test()
test();
function test(){
    console.log(this);
}

you will get Global/Window object.

  • But if you use the call method and pass an object:
test.call({name: "Harry Potter"});
function test(){
    console.log(this);
}

//output:- { name: 'Harry Potter' }

3rd Superpower

Duplicate parameter names are allowed, but this can be turned off if strict mode is on.

JavaScript: “Sure, go ahead, I’ll just use the last one anyway. No big deal.” 🙃
BUT — if you turn on strict mode ('use strict';), JavaScript suddenly becomes that one strict teacher (Math’s Teacher):

“Duplicate parameter names? In my class? Absolutely not!” 😠

So yeah, strict mode will throw an error and stop you from doing that.

Moral of the story: If you're not in strict mode, JavaScript lets you be messy. In strict mode, it's no nonsense ✋📏

test(1,2,3);
function test(num1, num2 , num1){
    console.log(num1, num2, num1);
}
//output:- 3 2 3
//it use the last one

4th Superpower

Used as a constructor call
When you call a function with the new keyword, like this:

function Car(n) {
  this.wheels = n;
}
const myCar = new Car(4);
console.log(myCar);
//output:- Car { wheels: 4 }

5th Superpower

built-in arguments array-like structure. It’s vary intresting superpower.
It’s not actuall array, it;s a array like structure

function showStuff() {
  console.log(arguments);
}
showStuff('Hello', 42, true);

// output:- [Arguments] { '0': 'Hello', '1': 42, '2': true }

The import thing you don’t need to give parameter to function for this.
You'll get something that looks like an array — it has length, you can access items with index (arguments[0], arguments[1], etc.) — but it doesn’t have real array powers like .map() or .forEach() 😅

So yes, it's an array-like object, not a true array.

🦸‍♂️ Bonus superpower: It captures all arguments passed to the function — even if you didn’t declare them in the parameter list! Sneaky, huh?

But then ES6 entered like a superhero! 🦸‍♂️
Now, if you want a real array of all your arguments, just do this:

function showStuff() {
  console.log([...arguments]);
}
showStuff('Hello', 42, true);

// or

function showStuff(..args) {
  console.log([...args]);
}
showStuff('Hello', 42, true);

//output:- [ 'Hello', 42, true ]

Just spread it and forget it: [...args]
Boom — real array, full power, no drama. 💪

Modern JavaScript for the win! 🥳

6th Superpower

Event Listner
this referes to element on which you have added event listener, When you add an event listener to an element, the value of this inside the callback refers to the element the event happened on.

const button = document.querySelector('button');

button.addEventListener('click', function () {
  console.log(this); // 👉 This refers to the button element
});

So here, this is pointing to the button — like it's proudly saying:

“Yep, I’m the one who got clicked. All eyes on me 😎”

🚨 But careful! If you use an arrow function instead:

button.addEventListener('click', () => {
  console.log(this); // 😬 This is NOT the button
});

Arrow functions don’t have their own this, so they just “borrow” it from the outer scope — which might not be the button at all!

So moral of the story:

Want this to be the clicked element? Use a regular function.

Or as JavaScript would say:

“Arrow functions are cool, but for event listeners, go old school!” 🧓📞

Arrow Functions: When JavaScript Got a Shortcut Key

Arrow functions were introduced in ES6 to solve a very specific (and very annoying) problem:

👉 The confusing behavior of this inside functions!

Before arrow functions, you'd write a regular function in an object or a class, and suddenly this would start pointing to something unexpected. It was like this had commitment issues. 😅

Arrow functions fix that by not having their own this — instead, they use the value of this from their surrounding (parent) scope.
So now, no more weird binding, no more that = this, and no more .bind(this) hacks! 🎉

Variations

//variation 1️⃣ Basic Arrow Function
const add = (a, b) => {
  return a + b;
};

//variation 2️⃣ One-liner with Implicit Return
const add = (a, b) => a + b;

//variation 3️⃣ Single Parameter (No Parentheses)
const square = x => x * x;

//variation 4️⃣ No Parameters (Use Empty Parentheses)
// To return something in one line, you don't need to use braces.
const greet = () => console.log("Hello!");

//variation 5️⃣ Returning an Object (Use Parentheses Around It)
const getUser = () => ({ name: "Alice", age: 25 });

//variation 6️⃣ Arrow Function as Callback
const numbers = [1, 2, 3];
const doubled = numbers.map(n => n * 2);

//variation 7️⃣ Use underscore
const add = (_, b) => { // underscore use to ignore that value, that i am not intrested in,
// _ underscore basically use to avoid linting error/warning.
console.log(b);
};
add(3, 4);

Some common cases when I ask someone why or when they use arrow functions:

  • Easy for Readable

  • New feature in JavaScript, so JavaScript recommends it.

  • Less Code we have to wight

The reasons listed above are not the valid reason for using Arrow Functions.

Curse of Arrow Function

  1. You have to read whole function body in order to find what this function is doing
// arrow function
[1,2,3,4].map((n)=>{
    console.log(n*n);
})

// traditional function
[1,2,3,4].map(function squareOfNumber(n){
    console.log(n*n);
})
  1. In the stack trace, it will show up as anonymous if you use an arrow function incorrectly.
    To avoid this always try to store arrow function a variable.
// arrow function
[1,2,3,4].map((n)=>{
    [null].filter((v)=>{
        v();
        return true;
    });
    return n*n;
})
// example for just showing error in console.

When use Arrow Function

When you want to write this aware code (preserving binding this across diffrent function call)

function Timer(){
    this.seconds = 0;
    setInterval(()=>{
        this.seconds++;
        console.log(this.seconds);
    },1000);
}
new Timer();
// in setInterval if you use traditional function
// then at time of console, this may lost it's state

In a class component, there's no need to bind manually.

class myComponent {
    constructor() {
        this.state = { name: "Harry" };
        // this.state = this.sayHi.bind(this); ❌ no need to bind manually
    }
    sayHi = () => {
        console.log(this.state.name);
    }
}
const obj = new myComponent();
obj.sayHi(); // { name: "Harry" }

In callbacks passed. Like in setTimeout, forEach etc.

const printer = {
    prefix: ">>",
    print(items){
        items.forEach((item)=>{
            console.log(this.prefix, item);
        });
    }
}
printer.print([2,1,4,5])
// you get error when replace arrow with traditional function in forEach

Function Like a Pro: No More JavaScript Crimes!

Best Practices for Functions (and Arrow Functions)

  1. Always assign a name to your callback functions – anonymous functions are the silent bugs of the future.

  2. Avoid one-character parameter names – unless you're writing a tiny utility, give your variables a real identity.

  3. Avoid passing functions inline – unless it's super short or throwaway.

  4. Prefer named callbacks – they’re easier to read, test, and reuse.

The Grand Function Finale: Use the Right Tool for the Right Job

And there you have it — the world of JavaScript functions, demystified and (hopefully) a bit more fun!

You've journeyed through:

  • The classic charm of traditional functions 👨‍🏫

  • The modern swagger of arrow functions 🏹

  • The mystery of function expressions, declarations, and definitions 🎭

  • And even peeked behind the curtain of this, parameters, and best practices ✨

If this blog were a movie, this would be the part where the mentor pats you on the back and says:

“You’ve got what it takes, bro. Now go write clean, readable, bug-squashing code.” 💻🔥

🧘‍♂️ Now Breathe...

You’ve just leveled up your function-fu.
The next time someone says, “JavaScript is weird,”
you can smile and say,

“Yeah. But now I speak its language.”

👋 Goodbye for Now — See You in the Next Blog!

If this post helped you understand functions a little better (or at least made you laugh once 😄), then my job here is done!

Got questions, feedback, or your own favorite function trick?
The comment section is all yours — don’t be shy!

Until next time,
Happy coding, stay curious, and may your this always point in the right direction! 🚀

9
Subscribe to my newsletter

Read articles from RIMANSHU SINGH directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

RIMANSHU SINGH
RIMANSHU SINGH

I'm a passionate frontend developer with a knack for crafting immersive user experiences. Over the years, I've honed my skills in ReactJS, MongoDB, Redux, React-Toolkit, and SQL, leveraging these tools to deliver robust and dynamic web applications. I am passionate about explore and learning new things and willing to work beyond my capacity to administer projects. 💼 Currently, Diving deep into MEAN stack