DEV Community

Cover image for JS Function Declarations vs. Expressions: The Architect vs. The Freelancer
kiran ravi
kiran ravi

Posted on

JS Function Declarations vs. Expressions: The Architect vs. The Freelancer

In the JavaScript world, how you define a function is just as important as what the function does. Choosing between a Function Declaration and a Function Expression isn't just about syntax—it’s about how the JavaScript engine treats your code in memory.

Think of it this way: One is like an Architect (planned and placed before the building starts), and the other is like a Freelancer (hired only when they are needed).


1. The Syntax: Spotting the Difference

The Function Declaration

This is a standalone statement. It starts with the function keyword and must have a name. It’s the "traditional" way of writing JS.

function calculateTotal(price, tax) {
    return price + (price * tax);
}

Enter fullscreen mode Exit fullscreen mode

The Function Expression

Here, a function is treated as a value. You define the function and assign it to a variable. These are often anonymous.

const calculateTotal = function(price, tax) {
    return price + (price * tax);
};

Enter fullscreen mode Exit fullscreen mode

2. The Battle of Hoisting (The Technical Deep-Dive)

This is the "Make or Break" difference. JavaScript executes code in two phases: Creation and Execution.

Declarations: The "Early Risers"

Function declarations are fully hoisted. During the creation phase, the JS engine moves the entire function definition to the top of its scope.

The Result: You can call a declaration before it appears in your code.

shout("Hello!"); // ✅ Works perfectly!

function shout(message) {
    console.log(message.toUpperCase());
}

Enter fullscreen mode Exit fullscreen mode

Expressions: The "Late Bloomers"

Function expressions are treated like any other variable. If you use const or let, the variable is hoisted but stays in the Temporal Dead Zone (TDZ) until the code reaches that line.

The Result: If you call an expression before defining it, your app will crash.

whisper("Secret..."); // ❌ ReferenceError: Cannot access 'whisper' before initialization

const whisper = function(message) {
    console.log(message.toLowerCase());
};

Enter fullscreen mode Exit fullscreen mode

3. Real-World Usage: When to Use Which?

Scenario A: The "Utility Belt" (Use Declarations)

If you are writing a complex file with many helper functions, use Declarations at the bottom of the file. This allows your main "business logic" to stay at the top of the file, calling helpers that the reader hasn't seen yet. It keeps the important stuff front and center.

Scenario B: Callbacks & Inline Logic (Use Expressions)

When you need to pass a function into another function (like map, filter, or addEventListener), Expressions are the way to go. They are clean, scoped, and don't pollute the global namespace.

// Using an expression as a callback
const prices = [10, 20, 30];
const doublePrices = prices.map(function(price) {
    return price * 2;
});

Enter fullscreen mode Exit fullscreen mode

Scenario C: Conditional Functions (Use Expressions)

Declarations are technically not supposed to be defined inside if blocks (though some browsers allow it, it's inconsistent). Expressions are perfect for this.

let greet;
if (isMorning) {
    greet = function() { console.log("Good Morning"); };
} else {
    greet = function() { console.log("Good Evening"); };
}

Enter fullscreen mode Exit fullscreen mode

4. Why Modern Devs Love Expressions (and Arrows)

Most modern style guides (like Airbnb’s) recommend Function Expressions (specifically Arrow Functions) assigned to const.

Why?

  1. Predictability: It forces you to define functions before using them, preventing the "spaghetti code" that hoisting can sometimes create.
  2. Immutability: Using const ensures the function cannot be overwritten later in the script.
  3. Clean Call Stacks: Using Named Function Expressions helps with debugging.
// Named Function Expression for better debugging
const login = function performLogin() {
   // If this crashes, 'performLogin' shows up in the stack trace
};

Enter fullscreen mode Exit fullscreen mode

Summary Table

Feature Function Declaration Function Expression
Hoisting Fully hoisted (Safe to call early) Not hoisted (Crashes if called early)
Parsing Loaded before code execution Loaded when the line is reached
Syntax Independent statement Part of an assignment
Main Benefit Flexibility and global access Scope control and clean flow

Final Verdict

  • Use Declarations for top-level, global-style helpers that you want available everywhere.
  • Use Expressions for everything else—especially for React components, callbacks, and keeping your code predictable.

Top comments (0)