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) |
ποΈ 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?
Frequently Asked Questions
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.