DEV Community

Cover image for Arrow Functions vs Function expressions
Faith Kimani
Faith Kimani

Posted on

Arrow Functions vs Function expressions

Introduction

Functions are the lifeblood of JavaScript, sort of like the baristas of the code world serving up your logic in neat little cups. But when it comes to brewing up functions, you pretty much have two big options: classic function expressions and sleek-and-modern arrow functions.

I mean, have you ever wondered how they differ? Is one faster, cooler, or plotting secretively against the other? Let's dive in and find out.

The Syntax Smackdown

All right, let's get things rolling with a small syntax comparison. Behold - the arrow function:

const functionName = (parameter1, parameter2) => "This is an implicit return";
Enter fullscreen mode Exit fullscreen mode

It's like taking an anonymous function and giving it a cool alias. Notice something? No function keyword. No fluff. Just action. The magic in action here is called implicit return, which lets you bypass curly braces {} and the return keyword—if it's just a single expression.

Here's an example:

const playMovie = movie => "Playing some " + movie;
console.log(playMovie("action")); // "Playing some action"

Enter fullscreen mode Exit fullscreen mode

One line, one return, zero drama.

But wait—what happens when your function needs to do a bit more heavy lifting? Enter the block body:

const playMusic = music => {
  return "Playing some " + music;
};
console.log(playMusic("Jazz")); // "Playing some Jazz"

Enter fullscreen mode Exit fullscreen mode

If you forget the return keyword here, JavaScript will just shrug and say, "Undefined it is!"

const playMusic = music => {
``
"Playing some " + music;
};
console.log(playMusic("Jazz")); // undefined
Enter fullscreen mode Exit fullscreen mode

So remember, curly braces come with strings attached: you need to explicitly return something.

The Parentheses Debate

Arrow functions also keep things minimal when dealing with a single parameter:

const playMovie = movie => "Playing some " + movie;
Enter fullscreen mode Exit fullscreen mode

No need for parentheses—it's shorthand heaven! But as soon as there's more than one parameter, you're back to wrapping things up:

const readBooks = (book1, book2) => `I read '${book1}' and '${book2}'`;
console.log(readBooks("The Old Man and the Sea", "1984")); // "I read 'The Old Man and the Sea' and '1984'"
Enter fullscreen mode Exit fullscreen mode

Try removing those parentheses there, and JavaScript will throw a Syntax Error, because apparently, it doesn't like ambiguity.

const readBooks = book1, book2 => `I read '${book1}' and '${book2}'`;
// Syntax Error

Enter fullscreen mode Exit fullscreen mode

So, Where Do Arrow Functions Shine?

Arrow functions are the cool kids in JavaScript—they really come alive with modern use cases such as array iteration. For example:

const numbers = [1, 2, 3, 4];
numbers.map(num => console.log(`This is ${num}`));
Enter fullscreen mode Exit fullscreen mode

Concise, readable, and just what you need when you want a quick function that does its thing once and then is discarded. They are almost like the hustle culture response to JavaScript: "Do more with less!"

When to Use Regular Functions

While arrow functions are great for simplicity, there are times when good old regular functions are your best bet:

Function Hoisting

Regular functions are hoisted, meaning you can call them before they’re defined in your code:

sayHello(); // "Hello, world!"

function sayHello() {
  console.log("Hello, world!");
}

Enter fullscreen mode Exit fullscreen mode

Arrow functions, on the other hand, are not hoisted. Try calling one before its declaration, and JavaScript will throw a fit.

Methods

When defining methods on objects, regular functions are the way to go. Why? Because they get their own this context, which points to the object they belong to.

const person = {
  name: "Alice",
  greet: function () {
    return `Hello, I’m ${this.name}`;
  }
};

console.log(person.greet()); // "Hello, I’m Alice"
Enter fullscreen mode Exit fullscreen mode

Arrow functions don’t have their own this. Instead, they inherit this from their surrounding scope, which can lead to unexpected results:

const person = {
  name: "Alice",
  greet: () => `Hello, I’m ${this.name}`
};

console.log(person.greet()); // "Hello, I’m undefined"
Enter fullscreen mode Exit fullscreen mode

Unless you’re specifically looking for a this context from the outer scope, stick to regular functions for object methods.

A Quick Note on the this Keyword

One of the most distinctive features of arrow functions is that they bind this. Whereas normal functions have their own this, arrow functions borrow theirs from their surroundings. It's almost like they never RSVP'd to the function party so now they just chill with their closest lexical environment.

That makes them ideal for cases that require preserving context, such as working with class methods or callbacks in modern frameworks.


Wrap-Up

Well, there you have it: the showdown between arrow functions and function expressions. One of the standout differences is that arrow functions don't use the function keyword. They also offer an implicit return for single expressions, automatically inferring the return value without requiring the return keyword or curly braces {}. However, when using a block body with curly braces, you must include an explicit return to avoid unexpected results.

Another distinction lies in parameter handling: with a single parameter, parentheses can be omitted for a cleaner look. But if there are multiple parameters, parentheses become mandatory to ensure clarity and avoid syntax errors.

It's not a matter of which one wins the contest; it is about picking the right tool for the job. As I like to think:

Arrow functions are the shots of espresso in JavaScript: strong, fast, and to the point. Function expressions? They're cappuccino classic: reliable, full-bodied, perfect for when sipping every detail.

Now go out there and function like a pro!

Top comments (0)