Arrow Function Syntax
Arrow functions use the => (fat arrow) notation instead of the function keyword.
// Full syntax (equivalent to a function expression)
const add = (a, b) => {
const result = a + b;
return result;
};
console.log(add(3, 4)); // 7
// Concise body (implicit return) β single expression, no braces
const multiply = (a, b) => a * b;
console.log(multiply(3, 4)); // 12
// Single parameter β parentheses optional
const square = n => n * n;
console.log(square(5)); // 25
// No parameters β empty parens required
const getRandomInt = () => Math.floor(Math.random() * 100);
console.log(typeof getRandomInt()); // number
Wrap object literals in parentheses to distinguish them from a block: const makeUser = name => ({ name, role: 'user' }). Without parens, {} is treated as a function body, not an object.
// Returning an object literal β must wrap in ()
const makeUser = (name, role) => ({ name, role, createdAt: new Date().toISOString() });
console.log(makeUser("Alice", "admin"));
Arrow vs Regular Function Comparison
| Feature | Arrow Function | Regular Function |
|---|---|---|
this binding | Lexical (inherits from enclosing scope) | Dynamic (depends on how called) |
arguments object | Not available | Available |
Can be constructor (new) | No (throws TypeError) | Yes |
prototype property | None | Has prototype |
| Implicit return | Yes (concise body) | No |
| Hoisted | No (it's an expression) | Yes (declarations) |
| Named for stack traces | Only if assigned to variable | Yes (if declaration) |
Lexical this Binding β The Key Difference
A regular function creates its own this when called. An arrow function has no this of its own β it uses the this of the enclosing code where the arrow function was defined.
// Problem with regular function inside a method
const timer = {
seconds: 0,
startRegular: function() {
// 'this' inside regular callback is NOT the timer object
setInterval(function() {
this.seconds++; // 'this' is undefined (strict) or window (non-strict)
console.log("Regular this.seconds:", this.seconds);
}, 1000);
},
startArrow: function() {
// Arrow function inherits 'this' from startArrow's scope (timer)
setInterval(() => {
this.seconds++;
console.log("Arrow this.seconds:", this.seconds); // Works!
}, 1000);
}
};
// Demonstrate lexical this with synchronous code
const counter = {
count: 0,
increment: function() {
const add = () => {
this.count++; // Arrow: 'this' is counter
};
add();
},
incrementBroken: function() {
const add = function() {
this.count++; // Regular: 'this' is undefined in strict mode
};
try { add(); } catch(e) { console.log("Error: " + e.message); }
}
};
counter.increment();
console.log(counter.count); // 1
Arrow Functions in Callbacks and Array Methods
Arrow functions are ideal for callbacks β they are concise and don't rebind this.
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// map β transform
const squares = numbers.map(n => n ** 2);
console.log(squares); // [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
// filter β keep matching
const evens = numbers.filter(n => n % 2 === 0);
console.log(evens); // [2, 4, 6, 8, 10]
// reduce β accumulate
const sum = numbers.reduce((acc, n) => acc + n, 0);
console.log(sum); // 55
// Chained
const result = numbers
.filter(n => n % 2 === 0)
.map(n => n * 10)
.reduce((acc, n) => acc + n, 0);
console.log(result); // 300
Object Method Gotcha
Do NOT use arrow functions as object methods when you need to access the object via this.
const user = {
name: "Alice",
// Arrow function β 'this' is NOT the user object
greetArrow: () => {
console.log("Hello, " + this?.name); // undefined or error
},
// Regular function β 'this' IS the user object
greetRegular: function() {
console.log("Hello, " + this.name); // Alice
},
// ES6 shorthand method (same as regular function)
greetShorthand() {
console.log("Hello, " + this.name); // Alice
}
};
user.greetRegular(); // Hello, Alice
user.greetShorthand(); // Hello, Alice
Arrow functions have no this, no prototype, and cannot be called with new. Use regular functions (or ES6 shorthand methods) when you need a method on an object or a constructor.
No arguments Object
// Regular function β has arguments
function regularSum() {
let total = 0;
for (let i = 0; i < arguments.length; i++) total += arguments[i];
return total;
}
console.log(regularSum(1, 2, 3)); // 6
// Arrow function β no arguments, use rest params instead
const arrowSum = (...nums) => nums.reduce((a, b) => a + b, 0);
console.log(arrowSum(1, 2, 3)); // 6
// Arrow inside regular β inherits outer arguments
function outer() {
const inner = () => {
console.log(arguments[0]); // Accesses outer's arguments
};
inner();
}
outer("hello"); // hello
When to Use Arrow vs Regular Functions
| Situation | Use Arrow | Use Regular |
|---|---|---|
| Callback in array methods | Yes | OK but verbose |
| Short inline functions | Yes | Fine |
Object method needing this | No | Yes |
| Constructor function | No | Yes |
Event handler needing this = element | No | Yes |
| Method in class body | Yes (field arrows) | Yes (prototype methods) |
| Recursive function | Only if assigned | Yes (named declaration) |
Arrow Functions and this: the Whole Point
Arrows aren't just shorter β they don't have their own this. They inherit it from the surrounding scope (lexical this). That's exactly what you want inside callbacks:
class Timer {
constructor() { this.seconds = 0; }
start() {
// β
arrow keeps `this` = the Timer instance
setInterval(() => { this.seconds++; }, 1000);
}
}
With a regular function, this inside the interval would be undefined (or window) β the old "cannot read property of undefined" bug that forced const self = this hacks.
Because arrows have no own this, don't use them for object methods that need the object, or DOM event handlers that rely on this being the element. Also, arrows have no arguments object and can't be constructors (new throws).
const obj = {
name: "Sara",
greet: () => `Hi ${this.name}` // β this is NOT obj
};
ποΈ Practical Exercise
Convert these regular function expressions to arrow functions (full and concise where appropriate):
const double = function(n) { return n * 2; };const greet = function(name) { return "Hello, " + name; };const isEven = function(n) { return n % 2 === 0; };const getUser = function(id) { const found = users.find(u => u.id === id); return found || null; };
π₯ Challenge Exercise
Create a TaskManager object with:
- A
tasksarray - An
addTask(task)method (regular function β modifiesthis.tasks) - A
getCompleted()method that uses an arrow function callback inside filter to return only completed tasks - A
processAll(fn)method that calls fn on each task using an arrow function inside forEach
Demonstrate why the callbacks inside the methods need to be arrows (this binding).
π Summary
- Arrow functions use
=>syntax and are more concise than function expressions. - Concise body (no braces) returns the expression implicitly β no
returnkeyword needed. - The most important difference: arrows have lexical this β they inherit
thisfrom the enclosing scope. - Do not use arrows as object methods or constructors.
- Arrows have no
argumentsobject β use rest parameters instead. - Perfect for callbacks, array method predicates, and any short inline function.
Interview Questions
- What is the key difference between an arrow function and a regular function regarding
this? - When would you NOT use an arrow function?
- What is implicit return in arrow functions? Show an example.
- Can arrow functions be used as constructors? Why or why not?
- Why are arrow functions preferred for array method callbacks?
Related Topics
FAQ
Yes: const fetchData = async (url) => { const res = await fetch(url); return res.json(); };. Just add async before the parameter list.
Almost always for readability. The exception is DOM event listeners where you want this to refer to the element that fired the event β in that case, use a regular function since arrows would capture the outer this.
new with an arrow function?+It throws a TypeError: ... is not a constructor. Arrow functions have no prototype property and cannot be used as constructors. Use a regular function or a class instead.

