What you'll learn
Quick Answer
Arrow functions are a compact ES6 syntax for writing functions using the => symbol. Their two headline features are implicit returns for one-line bodies and a "lexical this" that borrows this from the surrounding code instead of creating its own. Use them for short callbacks like map and filter and inside class methods; avoid them as object methods, constructors, or when you need the arguments object.
What are arrow functions?
Arrow functions are a shorter way to write functions in JavaScript, added in ES6 (2015). Instead of the function keyword, you use a "fat arrow" =>. JavaScript arrow functions show up everywhere in modern code, especially inside array methods like map and filter, and in React and Node.js projects.
They do two useful things. They cut down the amount of typing, and they handle the tricky this keyword in a more predictable way. Here is the same function written both ways so you can see the shape:
// Regular function
function add(a, b) {
return a + b;
}
// Arrow function
const add = (a, b) => {
return a + b;
};
add(2, 3); // 5Both do exactly the same job. In this tutorial we compare the two properly, walk through the syntax step by step, and show you exactly when to reach for each one.
Arrow syntax vs regular functions
A regular function has three parts: the function keyword, an optional name, and a body in braces. An arrow function drops the keyword and moves the arrow between the parameters and the body.
// Regular, named
function greet(name) {
return "Hello, " + name;
}
// Arrow, stored in a variable
const greet = (name) => {
return "Hello, " + name;
};One important difference: arrow functions are always anonymous. They have no name of their own, so you usually store them in a const to give them a name you can call later. You cannot write arrow myFunc() {} the way you write function myFunc() {}.
Another difference is hoisting. A regular function declaration is hoisted, so you can call it before it appears in the file. An arrow function assigned to a const is not, so it must be defined before you use it.
Implicit returns: skip the braces
This is where arrow functions really save space. If the whole body is a single expression, you can drop both the braces and the return keyword. The value of that expression is returned automatically. This is called an implicit return.
// With braces you must write return
const double = (n) => {
return n * 2;
};
// Single expression: braces and return disappear
const double = (n) => n * 2;
double(5); // 10There is one gotcha that catches almost everyone. If you want to return an object literal, the braces of the object look exactly like the braces of a function body. JavaScript reads them as a code block, not an object, and returns nothing.
// Wrong: braces are read as a function body
const makeUser = (name) => { name: name };
makeUser("Aarav"); // undefined
// Right: wrap the object in round brackets
const makeUser = (name) => ({ name: name });
makeUser("Aarav"); // { name: "Aarav" }The fix is simple: wrap the object in parentheses so JavaScript knows you mean a value, not a block.
The single-parameter shorthand
Arrow functions let you drop the parentheses around the parameter list when there is exactly one parameter. Zero parameters and two-or-more parameters still need the brackets.
// One parameter: brackets optional
const square = n => n * n;
// No parameters: empty brackets required
const now = () => Date.now();
// Two or more parameters: brackets required
const add = (a, b) => a + b;Our recommendation: even though the brackets are optional for one parameter, many teams keep them always. It keeps every function looking the same and it means you do not have to add brackets later when you introduce a second parameter. Popular formatters like Prettier add them back by default. Either style works, so just be consistent within a project.
How the this binding differs
This is the single most important reason arrow functions exist, and the part beginners find confusing. In a regular function, the value of this depends on how the function is called. That can change from one call to the next, and it often surprises people inside callbacks.
const counter = {
count: 0,
start() {
// Regular function: setInterval calls it with its own `this`
setInterval(function () {
this.count++; // `this` is NOT `counter` here
console.log(this.count); // NaN
}, 1000);
}
};Inside that regular callback, this is no longer the counter object, so this.count is missing and you get NaN. An arrow function fixes this because it does not have its own this. It borrows this from the code around it, which is called lexical this.
const counter = {
count: 0,
start() {
setInterval(() => {
this.count++; // arrow keeps `this` from start()
console.log(this.count); // 1, 2, 3...
}, 1000);
}
};Because the arrow was written inside start(), its this is the same as start()'s this, which is counter. Before ES6 people solved this with tricks like const self = this; or .bind(this). Arrow functions make all of that unnecessary.
Practical example: array callbacks
Array methods take a function as an argument (a "callback"), and this is where arrow functions read best. The short syntax and implicit return keep the focus on the logic.
const prices = [100, 250, 80, 500];
// map: transform every item (add 18% GST)
const withTax = prices.map(p => p * 1.18);
// [118, 295, 94.4, 590]
// filter: keep only some items
const affordable = prices.filter(p => p < 300);
// [100, 250, 80]
// reduce: combine into a single value
const total = prices.reduce((sum, p) => sum + p, 0);
// 930Notice there is no return and no braces: each callback is a single expression, so the implicit return does the work. Compare that to the older style with function and you can see why arrow functions became the default for callbacks.
Want to practice these array methods hands-on with more worked examples? Our free JavaScript course walks through map, filter, and reduce step by step, all in the browser with nothing to install.
Practical example: event handlers
Arrow functions are also common as DOM event handlers, but there is a catch worth knowing. In a regular handler function, this points to the element that fired the event. In an arrow handler, this does not point to the element, because the arrow borrows this from the surrounding scope.
const button = document.querySelector("#save");
// Regular function: `this` is the button
button.addEventListener("click", function () {
this.disabled = true;
});
// Arrow function: `this` is NOT the button
button.addEventListener("click", (event) => {
event.currentTarget.disabled = true; // use the event instead
});Recommendation: prefer event.currentTarget (or event.target) instead of relying on this. It reads clearly and works the same whether you use an arrow or a regular function, so you never have to remember which kind of this you are getting.
Inside a class component or a React handler, though, an arrow is usually what you want, because it keeps this pointing at the component instance without any extra binding.
When to use each one
Arrow functions are not a replacement for regular functions; they are a different tool. Here is a quick guide to which behaves how:
| Feature | Arrow function | Regular function |
|---|---|---|
| Shortest syntax for callbacks | Yes | No |
Has its own this | No | Yes |
| Good as an object method | No | Yes |
Can be used with new | No | Yes |
Has the arguments object | No | Yes |
| Is hoisted | No | Yes |
Use an arrow function for short callbacks (map, filter, reduce, setTimeout) and any time you want to keep the outer this, such as inside a class method. Use a regular function for object methods, constructors, and any function you plan to call with new.
Common gotchas to avoid
A few traps come up again and again. Knowing them now will save you a confusing debugging session later.
1. Do not use arrows as object methods
Because an arrow borrows this from the outside, it will not point to the object.
const user = {
name: "Priya",
greet: () => "Hi, " + this.name // `this` is NOT `user`
};
user.greet(); // not "Hi, Priya"Use the shorthand method syntax instead: greet() { return "Hi, " + this.name; }.
2. No arguments object
Arrow functions do not have the special arguments variable. If you need all the arguments, use a rest parameter, which works everywhere and is clearer anyway:
const sum = (...numbers) => numbers.reduce((a, b) => a + b, 0);
sum(1, 2, 3); // 63. They cannot be constructors
You cannot call an arrow function with new. It has no prototype, so new MyArrow() throws a TypeError. Use a regular function or a class for that.
4. Return objects with parentheses
As shown earlier, wrap an object literal in (...) when you use an implicit return, or JavaScript reads the braces as a code block.
Keep these four in mind and arrow functions become a reliable, everyday tool rather than a source of surprises.
Frequently Asked Questions
Are arrow functions faster than regular functions?
No, there is no meaningful speed difference in normal code. Choose between them based on the this behaviour and readability, not performance. Arrow functions exist to write cleaner callbacks and to handle this predictably, not to run faster.
Why does this show undefined inside my arrow function?
Because an arrow function does not create its own this; it borrows it from the surrounding scope. If that outer scope is a module or the top level in strict mode, this is undefined. If you need this to point to an object, use a regular method instead of an arrow.
Can I use arrow functions for everything?
No. Avoid them as object methods (their this will not point to the object), as constructors called with new, and when you need the arguments object. They are ideal for short callbacks and for keeping the outer this inside class methods.
What is an implicit return?
When an arrow function body is a single expression, you can drop the braces and the return keyword, and the value is returned automatically. For example, n => n * 2 returns n * 2 with no explicit return. To return an object literal this way, wrap it in parentheses.
Do arrow functions work in all browsers?
Yes, every modern browser has supported them since around 2016, so you can use them freely today. Only very old browsers like Internet Explorer 11 do not understand the syntax. If you must support such browsers, a build tool like Babel can convert arrow functions to regular ones for you.
