DEV Community

Cover image for Function Declaration vs Function Expression: What's the Difference?
Pratham
Pratham

Posted on

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

Two ways to write functions in JavaScript — and why the distinction actually matters.


Let me take you back to my first week of writing JavaScript. I had just learned how to write a function. Cool. Then I saw someone write the same function but in a completely different way — assigning it to a variable like a value. I stared at it for a solid minute thinking, "Wait, you can do that?"

Turns out, JavaScript gives you more than one way to create functions, and understanding the difference between them isn't just trivia — it affects how your code behaves in ways that can genuinely trip you up if you don't know what's going on.

Let's break it all down.


What Are Functions (And Why Do We Need Them)?

Before we compare anything, let's get clear on what a function actually is.

A function is a reusable block of code that performs a specific task. Instead of writing the same logic over and over, you write it once inside a function and then call that function whenever you need it.

Think of it like a recipe. You don't reinvent biryani from scratch every time you want to cook it. You follow the recipe (the function), give it the ingredients (the arguments), and get a delicious result (the return value).

Without a Function — Repetitive and Messy

// Calculating area of a rectangle in three different places
let area1 = 10 * 5;
let area2 = 8 * 3;
let area3 = 15 * 7;

console.log(area1); // 50
console.log(area2); // 24
console.log(area3); // 105
Enter fullscreen mode Exit fullscreen mode

With a Function — Clean and Reusable

function calculateArea(length, width) {
  return length * width;
}

console.log(calculateArea(10, 5)); // 50
console.log(calculateArea(8, 3)); // 24
console.log(calculateArea(15, 7)); // 105
Enter fullscreen mode Exit fullscreen mode

Same result, but now you have one place to update if the logic ever changes. That's the power of functions.

How a Function Call Works

1. You CALL the function     →  calculateArea(10, 5)
                                      │
2. JavaScript JUMPS to       →  function calculateArea(length, width) {
   the function definition           │
                                     ↓
3. Parameters receive        →  length = 10, width = 5
   the argument values               │
                                     ↓
4. The code EXECUTES         →  return 10 * 5
                                     │
                                     ↓
5. The result is RETURNED    →  50 goes back to where the function was called
                                     │
                                     ↓
6. Execution CONTINUES       →  console.log(50)
   from where you left off
Enter fullscreen mode Exit fullscreen mode

Now that we're clear on what functions are, let's talk about the two main ways to create them.


Function Declaration — The Classic Way

A function declaration (also called a function statement) is the traditional way to define a function. You've probably seen this one already.

Syntax

function functionName(parameters) {
  // Code to execute
  return result;
}
Enter fullscreen mode Exit fullscreen mode

Example

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

let sum = add(10, 5);
console.log(sum); // 15
Enter fullscreen mode Exit fullscreen mode

Key Characteristics

  • Starts with the function keyword
  • Has a name (in this case, add)
  • Can be called anywhere in the same scope — even before the declaration (more on this soon)
  • Stands on its own as a complete statement

Function declarations are straightforward. You name it, you define it, you call it. No surprises.


Function Expression — The "Store It in a Variable" Way

A function expression creates a function and assigns it to a variable. The function itself can be unnamed (anonymous) or named, but the variable is what you use to call it.

Syntax

const functionName = function (parameters) {
  // Code to execute
  return result;
};
Enter fullscreen mode Exit fullscreen mode

Notice that semicolon at the end? That's because this is a variable assignment statement, and those end with ;. It's a small detail, but it hints at something important: the function is being treated as a value — just like a number or a string.

Example

const add = function (a, b) {
  return a + b;
};

let sum = add(10, 5);
console.log(sum); // 15
Enter fullscreen mode Exit fullscreen mode

Key Characteristics

  • The function is assigned to a variable (add)
  • The function itself is usually anonymous (no name after function)
  • Can only be called after the line where it's defined
  • Ends with a semicolon because it's an assignment

Both approaches produce a function that works exactly the same way when called. add(10, 5) returns 15 in both cases. So why does JavaScript have two ways? The answer lies in hoisting.


The Big Difference: Hoisting

This is where things get interesting and where most beginners get confused. Let me explain it as simply as I can without going into deep execution context details.

What Is Hoisting? (The Simple Version)

Hoisting is JavaScript's behavior of moving declarations to the top of their scope before the code actually runs. Think of it as JavaScript doing a quick scan of your code before executing it, taking note of what's been declared.

But here's the catch: it doesn't hoist everything the same way.

Function Declarations ARE Hoisted ✅

You can call a function declaration before you write it in your code, and it works perfectly fine.

// Calling BEFORE the declaration — works!
let result = multiply(4, 5);
console.log(result); // 20

function multiply(a, b) {
  return a * b;
}
Enter fullscreen mode Exit fullscreen mode

JavaScript sees function multiply(...) during its initial scan, hoists the entire function to the top, and by the time your code runs, the function is already available. No errors.

Function Expressions Are NOT Hoisted ❌

Try the same thing with a function expression and you'll get an error.

// Calling BEFORE the expression — ERROR!
let result = multiply(4, 5); // ❌ ReferenceError: Cannot access 'multiply' before initialization

const multiply = function (a, b) {
  return a * b;
};
Enter fullscreen mode Exit fullscreen mode

Why? Because multiply is a variable declared with const (or let). JavaScript hoists the variable name, but not its value. At the time you try to call multiply(4, 5), the variable exists but hasn't been assigned the function yet. It's like trying to open a box that hasn't been packed yet.

Visual Summary

📜 Your Code (as you wrote it):         🔄 After Hoisting (how JS sees it):

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

─────────────────────────                ─────────────────────────

sayBye();                                // const sayBye;           ← variable hoisted
                                         //   but NOT assigned yet
const sayBye = function() {
  console.log("Bye!");                   sayBye();                    Error!
};
                                         const sayBye = function() {
                                           console.log("Bye!");
                                         };
Enter fullscreen mode Exit fullscreen mode

Side-by-Side Comparison

Here's everything in one clean table:

Feature Function Declaration Function Expression
Syntax function name() {} const name = function() {};
Hoisted? ✅ Yes — fully hoisted ❌ No — variable hoisted, value isn't
Can call before definition? ✅ Yes ❌ No — throws ReferenceError
Has a name? Always named Usually anonymous
Ends with ;? No Yes (it's a variable assignment)
Treated as a value? Not directly Yes — it's assigned to a variable
When to use General-purpose, top-level functions Callbacks, conditional definitions

When to Use Each Type

This was my biggest question early on: "Okay, I get the difference, but which one should I actually use?" Here's what I've learned:

Use Function Declarations When:

  • You want a straightforward, reusable function that's easy to find in your code
  • You want the function to be available throughout the entire scope (hoisting is handy here)
  • You're writing top-level utility functions that your whole program relies on
// Good use of declaration — utility function used everywhere
function formatPrice(amount) {
  return "" + amount.toFixed(2);
}

console.log(formatPrice(499)); // "₹499.00"
console.log(formatPrice(1299.5)); // "₹1299.50"
Enter fullscreen mode Exit fullscreen mode

Use Function Expressions When:

  • You want to assign a function to a variable for flexibility
  • You're passing a function as an argument (callback) to another function
  • You want to ensure the function can't be called before it's defined (enforcing order)
  • You're working with conditional function creation
// Good use of expression — callback passed to another function
const numbers = [1, 2, 3, 4, 5];

const doubled = numbers.map(function (num) {
  return num * 2;
});

console.log(doubled); // [2, 4, 6, 8, 10]
Enter fullscreen mode Exit fullscreen mode
// Good use of expression — conditional function
let greet;

let language = "Hindi";

if (language === "Hindi") {
  greet = function (name) {
    return "Namaste, " + name + "! 🙏";
  };
} else {
  greet = function (name) {
    return "Hello, " + name + "! 👋";
  };
}

console.log(greet("Pratham")); // "Namaste, Pratham! 🙏"
Enter fullscreen mode Exit fullscreen mode

My Personal Rule

When I'm writing a standalone function that I want to be clearly visible and accessible — I use a declaration. When I'm passing a function around or storing it for later — I use an expression. Both are valid. Neither is "better." It depends on context.


Let's Practice: Hands-On Assignment

Part 1: Function Declaration — Multiply Two Numbers

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

let result1 = multiply(6, 7);
console.log("Declaration result:", result1); // Declaration result: 42
Enter fullscreen mode Exit fullscreen mode

Part 2: Same Logic as a Function Expression

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

let result2 = multiplyExpr(6, 7);
console.log("Expression result:", result2); // Expression result: 42
Enter fullscreen mode Exit fullscreen mode

Part 3: Call Both BEFORE Defining — Observe the Difference

// Try calling the declaration before it's defined
console.log("Before declaration:", earlyMultiply(3, 4)); // 12 ✅ Works!

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

// Now try calling the expression before it's defined
// Uncomment the line below to see the error:
// console.log("Before expression:", earlyMultiplyExpr(3, 4)); // ❌ ReferenceError!

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

console.log("After expression:", earlyMultiplyExpr(3, 4)); // 12 ✅ Works after definition
Enter fullscreen mode Exit fullscreen mode

What You'll Observe

  • The function declaration works perfectly when called before its definition. Hoisting has your back.
  • The function expression throws a ReferenceError if you try to call it before the assignment. The variable exists (hoisted), but it hasn't been assigned the function yet.
  • After the assignment line, both behave identically.

Key Takeaways

  1. Functions are reusable blocks of code. They take inputs (parameters), do something, and optionally return a result. They keep your code DRY (Don't Repeat Yourself).
  2. Function declarations use the function keyword and are fully hoisted — you can call them anywhere in their scope, even before the line where they're written.
  3. Function expressions assign a function to a variable. They are not hoisted (the value isn't), so you must define them before calling them.
  4. Hoisting is JavaScript's behavior of moving declarations to the top before execution. Declarations get fully hoisted; expressions don't.
  5. Use declarations for clear, top-level functions. Use expressions for callbacks, conditional logic, and when you want to enforce definition order.

Wrapping Up

When I first encountered both forms, I thought it was just JavaScript being weird and giving us two ways to do the same thing. But once I understood hoisting and started using callbacks (especially with array methods like .map() and .filter()), the difference clicked. Both forms have their place, and knowing when to use which one is a small but meaningful step toward writing cleaner, more intentional JavaScript.

I'm currently working through the ChaiCode Web Dev Cohort 2026 under Hitesh Chaudhary and Piyush Garg, and these are the kinds of fundamentals that keep paying off as the topics get more advanced. If you're learning alongside me, I hope this article saved you from some of the confusion I went through.

Connect with me on LinkedIn or check out my work at PrathamDEV.in. More articles on the way as I keep building and learning.

Happy coding! 🚀


Written by Pratham Bhardwaj | Web Dev Cohort 2026, ChaiCode

Top comments (0)