Regular Functions vs. Arrow Functions: Key Differences and When to Use Each
Regular functions and arrow functions aren't just different ways to write the same thing — they actually behave differently, and the most important difference is how they handle this.
- Syntax
- The
thisDifference - The
argumentsDifference - Constructor Functions
- Hoisting
- Quick Reference
- When to Use Each
Syntax
Regular function:
function plus(a, b) {
return a + b;
}Arrow function:
const plus = (a, b) => a + b;Arrow functions are more concise and support implicit returns — a natural fit for short callbacks and simple expressions.
The this Difference
This is the most important difference between the two.
Regular Functions
In a regular function, this is dynamic — it depends on who calls the function.
const obj = {
value: 10,
show: function () {
console.log(this.value); // 10
}
};
obj.show();this refers to obj because obj is the one calling show.
Arrow Functions
Arrow functions don't have their own this. Instead, they inherit it from the surrounding lexical scope.
const obj = {
value: 10,
show: () => {
console.log(this.value); // undefined
}
};
obj.show();this doesn't point to obj — it points to whatever this is in the outer scope.
Real-World Example: setTimeout
The difference becomes especially clear in async contexts.
Regular function:
const timer = {
seconds: 0,
start: function () {
setTimeout(function () {
this.seconds++; // `this` is not `timer`
console.log(this.seconds); // NaN
}, 1000);
}
};Arrow function:
const timer = {
seconds: 0,
start: function () {
setTimeout(() => {
this.seconds++; // `this` is `timer`
console.log(this.seconds); // 1
}, 1000);
}
};The arrow function inherits this from start, so it correctly accesses timer.seconds.
The arguments Difference
Regular functions have a built-in arguments object that holds all passed-in values:
function test() {
console.log(arguments); // [1, 2, 3]
}
test(1, 2, 3);Arrow functions don't have their own arguments:
const test = () => {
console.log(arguments); // ReferenceError (or outer scope's arguments)
};If you need to handle a variable number of arguments in an arrow function, use a rest parameter instead:
const test = (...args) => {
console.log(args); // [1, 2, 3]
};Constructor Functions
Regular functions can be used as constructors:
function Person(name) {
this.name = name;
}
const p = new Person("Charmy");
console.log(p.name); // "Charmy"Arrow functions cannot — they have no prototype and don't support new:
const Person = (name) => {
this.name = name;
};
new Person("Charmy"); // TypeErrorHoisting
Function declarations are hoisted, so you can call them before they're defined:
greet(); // "Hello"
function greet() {
console.log("Hello");
}Arrow functions are expressions and are not hoisted:
greet(); // ReferenceError
const greet = () => {
console.log("Hello");
};Quick Reference
| Regular Function | Arrow Function | |
|---|---|---|
| Syntax | More verbose | Concise |
this | Dynamic, depends on the caller | Inherited from outer scope |
arguments | Available | Not available (use rest params) |
| Constructor | Supported | Not supported |
| Hoisting | Hoisted | Not hoisted |
When to Use Each
Use Arrow Functions
Array methods with short logic:
const doubled = [1, 2, 3].map(n => n * 2);
const evens = [1, 2, 3, 4].filter(n => n % 2 === 0);Promise chains:
fetch(url)
.then(response => response.json())
.then(data => console.log(data));Callbacks that need to preserve the outer this:
setTimeout(() => {
this.update();
}, 1000);Use Regular Functions
Object methods that need to access this:
const user = {
name: "Charmy",
greet() {
console.log(this.name); // "Charmy"
}
};Constructor functions:
function Person(name) {
this.name = name;
}When hoisting matters — for example, placing function definitions at the bottom of a file:
init();
function init() {
// works fine
}Conclusion
Regular functions and arrow functions each have their place.
Need dynamic this? Use a regular function. Need to inherit it from the outer scope? Use an arrow function.
Concise syntax is a nice perk of arrow functions, but it shouldn't be the only reason you reach for one. Understanding the differences is what lets you pick the right tool for the job.