Frontend Development 9 min read

When to Use Arrow Functions vs Traditional Functions in JavaScript

This article explains the fundamental differences between arrow functions and traditional functions in JavaScript, shows five common scenarios where using a regular function is essential, and highlights the best situations to prefer arrow functions for concise, lexical this binding.

JavaScript
JavaScript
JavaScript
When to Use Arrow Functions vs Traditional Functions in JavaScript

Since ES6, arrow functions (

()=>{}

) have become popular among JavaScript developers because of their concise syntax and lexical

this

binding.

However, arrow functions are not a silver bullet; they cannot fully replace the traditional

function

keyword. Overusing them, especially without understanding their behavior, can cause hard‑to‑track bugs because the handling of

this

differs fundamentally between arrow functions and regular functions.

Core differences quick memo:

function : the value of

this

is determined dynamically when the function is called, based on the caller.

=> (arrow function): it has no own

this

; it captures the

this

value from the surrounding lexical context, which remains fixed.

Understanding this explains why in the following five scenarios using

function

is either the best practice or the only correct choice.

Scenario 1: Object Methods

When defining a method on an object we usually want

this

to refer to the object itself so that its properties can be accessed.

❌ Wrong example (arrow function):

<code>const person = {
  name: '老王',
  age: 30,
  sayHi: () => {
    // this comes from the global scope (window in browsers), not the person object
    console.log(`大家好,我是 ${this.name}`);
  }
};
person.sayHi(); // outputs: "大家好,我是 " (or undefined)
</code>

In this example the arrow function

sayHi

captures the global

this

, so

this.name

is undefined.

✅ Correct approach (function):

<code>const person = {
  name: '老王',
  age: 30,
  sayHi: function() {
    // this is dynamically bound to the person object when called
    console.log(`大家好,我是 ${this.name}`);
  },
  // ES6 method shorthand, which is also a function
  sayHiShorthand() {
    console.log(`大家好,我是 ${this.name}`);
  }
};
person.sayHi(); // "大家好,我是 老王"
person.sayHiShorthand(); // "大家好,我是 老王"
</code>

Conclusion: When a method needs to reference the object’s own properties, use

function

or the ES6 method shorthand.

Scenario 2: DOM Event Listeners

When using

addEventListener

we often need to access the element that triggered the event. A regular

function

automatically binds

this

to that element.

❌ Wrong example (arrow function):

<code>const button = document.getElementById('myButton');
button.addEventListener('click', () => {
  // this is still window or undefined, not the button element
  this.classList.toggle('active'); // TypeError
});
</code>

Here the arrow function captures the outer

this

, so the button cannot be accessed.

✅ Correct approach (function):

<code>const button = document.getElementById('myButton');
button.addEventListener('click', function() {
  // this correctly refers to the button element
  console.log(this); // <button id="myButton">...</button>
  this.classList.toggle('active'); // works as expected
});
</code>

Conclusion: In event‑handler callbacks, use

function

when you need

this

to refer to the event target.

Scenario 3: Constructor Functions

Arrow functions cannot be used as constructors. Calling an arrow function with

new

throws an error because they lack their own

this

and

prototype

properties.

❌ Wrong example (arrow function):

✅ Correct approach (function or class):

Conclusion: Never use an arrow function as a constructor; use a regular

function

or a

class

instead.

Scenario 4: Prototype Methods

When adding methods to a constructor’s

prototype

, we also want

this

to refer to the instance that calls the method.

❌ Wrong example (arrow function):

✅ Correct approach (function):

Conclusion: When defining methods on

prototype

, use

function

so that

this

points to the instance.

Scenario 5: Functions that Need arguments

Arrow functions do not have their own

arguments

object; they inherit it from the nearest non‑arrow function. If you need a true

arguments

object, a regular function is required.

❌ Wrong example (arrow function):

✅ Correct approach (function):

In modern JavaScript, rest parameters (

...args

) are preferred for variable‑arity functions, but when maintaining legacy code that relies on

arguments

, a regular

function

is the only viable choice.

When should you use arrow functions?

Arrow functions remain extremely useful, especially for their lexical

this

binding, which eliminates the need for patterns like

var self = this

or

.bind(this)

.

Best use cases:

Callback functions : in array methods such as

map

,

filter

,

forEach

, or in

setTimeout

,

Promise.then

, when you need to preserve the outer

this

context.

<code>const timer = {
  seconds: 0,
  start() {
    setInterval(() => {
      // this correctly refers to timer because the arrow function captures start's this
      this.seconds++;
      console.log(this.seconds);
    }, 1000);
  }
};
timer.start();
</code>
JavaScriptbest practicesarrow functionsthis bindingfunction keyword
JavaScript
Written by

JavaScript

Provides JavaScript enthusiasts with tutorials and experience sharing on web front‑end technologies, including JavaScript, Node.js, Deno, Vue.js, React, Angular, HTML5, CSS3, and more.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.