Skip to main content

Command Palette

Search for a command to run...

Arrow Functions in JavaScript: A Simpler Way to Write Function

Updated
โ€ข11 min readโ€ขView as Markdown

1. What Are Arrow Functions?

When you first learned JavaScript, someone showed you this:

function greet(name) {
  return "Hello, " + name;
}

It works. It's fine. But JavaScript developers got tired of typing function and return and curly braces every single time. So in 2015, JavaScript introduced arrow functions โ€” a shorter, cleaner way to write the same thing.

Here's the same function, rewritten as an arrow function:

const greet = (name) => "Hello, " + name;

That's it. One line. No function keyword. No return. No curly braces. Same result.

๐Ÿ”ฅ Gotcha #1 โ€” Arrow functions don't have their own name

A regular function has a name baked into it:

function greet() {}  // "greet" is the function's actual name

An arrow function is anonymous by default. It only gets a name because you stored it in a variable:

const greet = () => {}  // the function itself has no name โ€” the variable does

Why does this matter? When your code crashes and shows an error stack trace, a regular function shows its name clearly. An arrow function might just say anonymous. This makes debugging slightly harder in big projects. Not a dealbreaker, just something nobody tells you.

๐Ÿ”ฅ Gotcha #2 โ€” Arrow functions are NOT hoisted

Regular functions get "hoisted" โ€” JavaScript reads your entire file first and moves all function declarations to the top. So this works:

sayHi();  // โœ… Works! Even though sayHi is defined below

function sayHi() {
  console.log("Hi!");
}

Arrow functions? Nope.

sayHi();  // โŒ CRASH โ€” Cannot access 'sayHi' before initialization

const sayHi = () => {
  console.log("Hi!");
}

Arrow functions live inside const or let, which are NOT hoisted. So you must define the arrow function before you call it. Always.

2. Basic Arrow Function Syntax

Let's break down the anatomy piece by piece. This is the full syntax:

const functionName = (parameters) => {
  // body
  return value;
}

Let's compare this side by side with a normal function doing the same job:

// NORMAL FUNCTION
function add(a, b) {
  return a + b;
}

// ARROW FUNCTION โ€” exact same thing
const add = (a, b) => {
  return a + b;
}

Now, the parts that changed:

  • function add became const add

  • The = sign appeared between the name and parameters

  • The => arrow appeared after the parameters

  • Everything inside the body stays the same

That => is why they're called arrow functions. It literally looks like an arrow pointing at what the function does.

The Three Forms of Arrow Function Syntax

Here's where people get confused โ€” arrow functions have three different ways to write them, and JavaScript lets you pick based on how simple your function is.

Form 1 โ€” Full body (same as normal function, just with arrow):

const multiply = (a, b) => {
  const result = a * b;
  return result;
}

Use this when you have multiple lines of logic inside.

Form 2 โ€” Single expression, still has return:

const multiply = (a, b) => {
  return a * b;
}

Use this when you have one line but want to be explicit.

Form 3 โ€” No curly braces, no return (implicit return):

const multiply = (a, b) => a * b;

Use this for the simplest, one-liner functions.

We'll go deep on Form 3 (implicit return) in section 5. It's powerful but has traps.

3. Arrow Functions With One Parameter

Here's a special rule that makes arrow functions even shorter: if you have exactly one parameter, you can remove the parentheses.

// With parentheses โ€” always valid
const double = (n) => n * 2;

// Without parentheses โ€” also valid, one parameter only
const double = n => n * 2;

Both are identical. The second one is slightly shorter. Many JavaScript developers prefer dropping the parens for single-parameter functions.

More examples:

const square = n => n * n;
const shout = message => message.toUpperCase();
const isEven = n => n % 2 === 0;
const addExclamation = text => text + "!";

Clean. Simple. Readable.

When Would You Actually Use This?

The most common place you'll see single-parameter arrow functions is inside array methods like map, filter, and forEach:

const numbers = [1, 2, 3, 4, 5];

const doubled = numbers.map(n => n * 2);
// doubled = [2, 4, 6, 8, 10]

const evens = numbers.filter(n => n % 2 === 0);
// evens = [2, 4]

This is where arrow functions shine the most. Compare the same thing with a normal function:

// Normal function โ€” verbose
const doubled = numbers.map(function(n) {
  return n * 2;
});

// Arrow function โ€” clean
const doubled = numbers.map(n => n * 2);

The arrow function version reads almost like English: "take every n, and return n times 2."

๐Ÿ”ฅ Gotcha #4 โ€” No parentheses only works with EXACTLY one parameter

Zero parameters? You need parentheses (or _ as a convention):

const sayHello = () => "Hello!";   // โœ… correct
const sayHello = => "Hello!";      // โŒ syntax error

Two parameters? You need parentheses:

const add = a, b => a + b;         // โŒ syntax error
const add = (a, b) => a + b;       // โœ… correct

One parameter with a default value? You need parentheses:

const greet = name = "World" => "Hello " + name;   // โŒ syntax error
const greet = (name = "World") => "Hello " + name; // โœ… correct

One parameter with destructuring? You need parentheses:

const getName = {name} => name;           // โŒ syntax error
const getName = ({name}) => name;         // โœ… correct

The "no parens" shortcut only works for the simplest case: one plain variable parameter, nothing else.

๐Ÿ”ฅ Gotcha #5 โ€” Rest parameters work, but the syntax trips people up

You can use rest parameters (...args) in arrow functions:

const sum = (...numbers) => numbers.reduce((total, n) => total + n, 0);
console.log(sum(1, 2, 3, 4, 5));  // 15

This works perfectly. But here's what trips people up โ€” you might think since it's "one thing" (the rest array), you can skip parentheses:

const sum = ...numbers => numbers.reduce(...);  // โŒ syntax error

Nope. Rest parameters always need parentheses, even though it feels like "one parameter."

๐Ÿ”ฅ Gotcha #6 โ€” Destructured parameters look weird in arrow functions

When you destructure in a normal function:

function displayUser({ name, age }) {
  return name + " is " + age;
}

In an arrow function:

const displayUser = ({ name, age }) => name + " is " + age;

The curly braces {} inside the parentheses look confusing at first. People sometimes read it as "the function body is starting." It's not โ€” it's destructuring syntax inside the parameter list. The actual function body is after the =>.

4. Implicit Return vs Explicit Return

This is where arrow functions get their real superpower โ€” and their sneakiest traps.

Explicit Return โ€” What You Already Know

Every normal function uses explicit return. You write return and JavaScript knows what to send back:

const add = (a, b) => {
  return a + b;  // explicit โ€” you're explicitly saying "return this"
}

Arrow functions with curly braces also need explicit return. If you have {}, you must write return or the function returns undefined.

const add = (a, b) => {
  a + b;  // โŒ NO return keyword โ€” returns undefined silently!
}

This is one of the most common bugs beginners make. The function runs, does the math, but throws the result in the trash because there's no return.

Implicit Return โ€” The Arrow Function Magic Trick

When you remove the curly braces, the arrow function automatically returns whatever expression follows the arrow. You don't write return at all:

const add = (a, b) => a + b;  // implicitly returns a + b

JavaScript sees no curly braces โ†’ assumes you want to return the single expression.

More examples:

const square = n => n * n;                    // returns n * n
const isEven = n => n % 2 === 0;              // returns true or false
const greet = name => `Hello, ${name}!`;      // returns a string
const getFirstItem = arr => arr[0];           // returns first element

This is beautiful for simple, single-purpose functions.

๐Ÿ”ฅ Gotcha #7 โ€” Implicitly returning an object literal BREAKS silently

What if you want to implicitly return an object? You'd try this:

const makeUser = (name, age) => { name: name, age: age };

This does not work. JavaScript sees the { and thinks it's the function body opening, not an object literal. It will either throw an error or silently return undefined.

The fix: wrap the object in parentheses:

const makeUser = (name, age) => ({ name: name, age: age });
//                               ^                          ^
//                         parentheses tell JS "this is an expression"

Or with shorthand property names:

const makeUser = (name, age) => ({ name, age });

This is one of those things that will bite you exactly once, and then you'll never forget it.

๐Ÿ”ฅ Gotcha #8 โ€” Multi-line implicit return doesn't exist

People try to do this:

const calculate = (a, b) =>
  const result = a + b;   // โŒ syntax error
  result * 2;

Implicit return is one expression only. The moment you need multiple lines or variable declarations, you must use curly braces and an explicit return:

const calculate = (a, b) => {
  const result = a + b;
  return result * 2;  // โœ… explicit return
}

No shortcuts for multi-step logic.

๐Ÿ”ฅ Gotcha #9 โ€” Implicit return with a ternary (the beautiful one)

One implicit return pattern that looks intimidating but is actually elegant:

const grade = score => score >= 90 ? "A" : score >= 70 ? "B" : "C";

This is a ternary inside implicit return. It reads as: "if score โ‰ฅ 90 return A, else if score โ‰ฅ 70 return B, else return C." One line, no curly braces, no return keyword. Very common in real JavaScript codebases.

5. Arrow Functions vs Normal Functions โ€” The Real Differences

Most tutorials at this point write three paragraphs about this and make your eyes glaze over. We're not doing that. Let's cover the practical differences you'll actually hit.

Difference 1 โ€” Syntax (The Obvious One)

// Normal function
function add(a, b) {
  return a + b;
}

// Arrow function
const add = (a, b) => a + b;

Arrow functions are shorter. For simple utility functions, this readability win is the main reason to use them.

Difference 2 โ€” Arrow Functions Can't Be Used as Constructors

You know how you can do this with normal functions?

function Person(name) {
  this.name = name;
}

const person = new Person("Alice");  // โœ… works

With arrow functions:

const Person = (name) => {
  this.name = name;
}

const person = new Person("Alice");  // โŒ TypeError: Person is not a constructor

Arrow functions fundamentally cannot be used with new. They're not built for it. If you're building objects with constructors, use normal functions or classes.

Difference 3 โ€” No arguments Object

Normal functions have a secret variable called arguments that contains all the values passed to them:

function logAll() {
  console.log(arguments);  // works! shows all arguments
}

logAll(1, 2, 3);  // Arguments [1, 2, 3]

Arrow functions do NOT have arguments:

const logAll = () => {
  console.log(arguments);  // โŒ ReferenceError: arguments is not defined
}

If you need to capture all arguments in an arrow function, use rest parameters:

const logAll = (...args) => {
  console.log(args);  // โœ… [1, 2, 3]
}

๐Ÿ”ฅ Gotcha #10 โ€” Arrow functions inside objects behave unexpectedly (the this trap, briefly)

If you put an arrow function as a method inside an object, it breaks in a subtle way:

const person = {
  name: "Alice",
  greet: () => {
    return "Hello, I am " + this.name;  // โŒ this.name is undefined!
  }
}

console.log(person.greet());  // "Hello, I am undefined"

Why? Arrow functions don't have their own this. They borrow this from the surrounding context โ€” which here is the global scope, not the object.

The fix is simple: use a normal function for object methods:

const person = {
  name: "Alice",
  greet: function() {
    return "Hello, I am " + this.name;  // โœ… works correctly
  }
}

Rule of thumb: Arrow functions as object methods = danger zone. Normal functions as object methods = safe.

More from this blog

blog about web dev

52 posts