Skip to main content

Command Palette

Search for a command to run...

Function Declaration vs Function Expression: What's the Difference?

Published
7 min read
Function Declaration vs Function Expression: What's the Difference?

By Saurabh Prajapati | IBM Software Engineer | WebDev Cohort 2026


Why I Wanted to Explore This

When I first started writing JavaScript, I would just write functions like this and move on:

function greet() {
  console.log("Hello!");
}

Simple enough, right? But then I started seeing code like this all over the place:

const greet = function() {
  console.log("Hello!");
}

Wait... aren't these doing the same thing? Why would anyone write it differently?

Let me walk you through everything I discovered.


First, What Even Is a Function?

Before we compare, let's get on the same page.

A function is just a reusable block of code. Instead of writing the same logic again and again, you wrap it in a function and call it whenever you need it.

Think of it like a recipe. You write the steps once, and then you can "use" that recipe anytime you want to cook that dish.

Here's the simplest example:

function addNumbers(a, b) {
  return a + b;
}

console.log(addNumbers(3, 5)); // Output: 8
console.log(addNumbers(10, 20)); // Output: 30

You write the logic once. You reuse it everywhere. That's the power of functions.


Function Declaration

This is the classic way. You've probably seen it a hundred times.

function multiply(a, b) {
  return a * b;
}

console.log(multiply(4, 5)); // Output: 20

The syntax is straightforward:

  • Start with the function keyword

  • Give it a name (multiply)

  • Define the parameters inside ()

  • Write the logic inside {}

That's it. Clean, simple, readable.


Function Expression

Now here's where it gets interesting.

In a function expression, you create a function and assign it to a variable.

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

console.log(multiply(4, 5)); // Output: 20

Notice what changed:

  • No function name after the function keyword (this is called an anonymous function)

  • The function is stored inside a const variable called multiply

  • There's a ; at the end (because it's a variable assignment)

The result is the same. But how JavaScript treats these two approaches behind the scenes? Very different.


Side-by-Side Comparison

Here's a quick visual to make it stick:

┌─────────────────────────────────┬─────────────────────────────────────┐
│      Function Declaration       │        Function Expression          │
├─────────────────────────────────┼─────────────────────────────────────┤
│ function greet() { ... }        │ const greet = function() { ... };   │
├─────────────────────────────────┼─────────────────────────────────────┤
│ Has a name always               │ Usually anonymous                   │
├─────────────────────────────────┼─────────────────────────────────────┤
│ Hoisted (can call before it's   │ NOT hoisted (must define first,     │
│ defined)                        │ then call)                          │
├─────────────────────────────────┼─────────────────────────────────────┤
│ Great for utility functions     │ Great for callbacks, passing        │
│ used everywhere                 │ functions around                    │
├─────────────────────────────────┼─────────────────────────────────────┤
│ Defined at parse time           │ Defined at runtime                  │
└─────────────────────────────────┴─────────────────────────────────────┘

The Big Difference: Hoisting

Okay, this is the part that tripped me up the most. Let me explain it simply.

Hoisting means JavaScript reads through your code before running it and "moves" certain things to the top. Not literally — but it behaves that way.

Function Declarations Are Hoisted ✅

// Calling BEFORE the function is defined
console.log(greet()); // Output: "Hello!"

function greet() {
  return "Hello!";
}

Wait — how did this work? We called greet() before we even wrote the function!

That's hoisting. JavaScript saw the function declaration, mentally "lifted" it to the top, and made it available everywhere in the file.

Function Expressions Are NOT Hoisted ❌

// Calling BEFORE the function expression is defined
console.log(greet()); // ❌ Error: Cannot access 'greet' before initialization

const greet = function() {
  return "Hello!";
};

This throws an error. Because greet is just a variable here. And variables declared with const or let are not available before their line in the code.

I made this mistake early on. I was confused why one worked and the other didn't. Now I know exactly why.

Key rule to remember:

  • Function declaration → Call it anywhere in the file ✅

  • Function expression → Must define it first, then call ✅


When Should You Use Each One?

Honestly, this is a judgment call. But here's how I think about it:

Use Function Declaration when:

  • The function is a general utility used across many places

  • You want the flexibility to call it anywhere in your file

  • You're defining named, standalone functions

// Good use of declaration - utility function used everywhere
function formatDate(date) {
  return new Date(date).toLocaleDateString();
}

Use Function Expression when:

  • You're passing a function as an argument (callback)

  • You want to conditionally define a function

  • You're using arrow functions (a modern form of expression)

// Good use of expression - passing as a callback
const numbers = [1, 2, 3, 4];
const doubled = numbers.map(function(num) {
  return num * 2;
});

console.log(doubled); // [2, 4, 6, 8]

A Quick Look at Arrow Functions (Bonus)

You've probably seen this syntax too:

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

console.log(multiply(3, 4)); // Output: 12

Arrow functions are a shorter form of function expressions. They're very popular in modern JavaScript.

Same rules apply — they are NOT hoisted.


Assignment: Try It Yourself

Here's a small challenge to solidify your understanding:

Step 1 — Write a Function Declaration

function multiplyDeclaration(a, b) {
  return a * b;
}

console.log(multiplyDeclaration(6, 7)); // Expected: 42

Step 2 — Write the Same as a Function Expression

const multiplyExpression = function(a, b) {
  return a * b;
};

console.log(multiplyExpression(6, 7)); // Expected: 42

Step 3 — Try Calling Before Defining

// Test hoisting behavior

console.log(multiplyDeclaration(3, 3)); // ✅ Works — 9
console.log(multiplyExpression(3, 3)); // ❌ Error — try it!

function multiplyDeclaration(a, b) {
  return a * b;
}

const multiplyExpression = function(a, b) {
  return a * b;
};

Run this in your browser console or Node.js. See the error with your own eyes. That experience will make hoisting click better than any explanation.


What I Wish I Knew Earlier

A few quick "I wish I knew this" moments:

  • The name on a function expression is optional — but you can name it for better stack traces in errors

  • Arrow functions are expressions too — same hoisting rules apply

  • var behaves differently from const/let with hoisting — but that's a rabbit hole for another day

  • Most modern codebases use both — don't feel like you have to pick just one


Key Takeaways

Let's wrap up what we covered:

  • A function is a reusable block of code

  • Function declaration uses the function keyword with a name — hoisted ✅

  • Function expression assigns a function to a variable — not hoisted ❌

  • Use declarations for general-purpose utilities

  • Use expressions for callbacks and dynamic logic

  • Arrow functions are a modern shorthand for expressions


About the Author

Saurabh Prajapati is a Full-Stack Software Engineer at IBM India Software Lab, working on enterprise-level cloud-native solutions using Maximo. He specializes in GenAI, React, and modern web technologies, and loves sharing his learning journey with other developers.

More from this blog