Function Declaration vs Function Expression: What’s the Difference?
Source: Dev.to
Topics To Cover
- What functions are and why we need them
- Function declaration syntax
- Function expression syntax
- Key differences between declaration and expression
- Basic idea of hoisting (very high level)
- When to use each type
What functions are and why we need them
A function in programming is a self‑contained, named block of code that performs a specific task.
Think of it as a black‑box: it takes some input, processes it, and returns an output.
Analogy – a vending machine
| Part | Description |
|---|---|
| Input (arguments) | You insert money and press a button. |
| Body (function) | The internal mechanics check stock, decide which item to dispense, and calculate change. |
| Output (return value) | The machine drops the selected item and any change. |
Why we need functions?
You don’t have to know how the vending machine works each time you want a snack. You only need to know how to use its interface. Similarly, functions let you reuse logic without re‑implementing it.
Function declaration syntax
A function declaration uses the function keyword, followed by a name and an optional list of parameters. Its body contains statements that run when the function is called.
Syntax
function functionName(parameter1, parameter2, ...) {
// code to be executed
return value; // optional
}
function– required keyword that signals a function definition.functionName– identifier; follows the same naming rules as variables (camelCase is common).(…)– parentheses that enclose optional parameters, which become local variables inside the function.{…}– curly braces that contain the statements executed when the function is called.return– optional statement that sends a value back to the caller.
Example
// Function declaration
function calculateSum(a, b) {
return a + b;
}
// Invoking (calling) the function
const result = calculateSum(2, 5);
console.log(result); // output: 7
In this example:
calculateSumtakes two arguments (aandb) and returns their sum.- The returned value is stored in the constant
result. console.logprints the result (7) to the console.
Function expression syntax
A function expression defines a function as part of a larger expression, typically by assigning it to a variable. It is not executed until the code reaches the point where the variable is invoked. Unlike a declaration, a function expression can be anonymous (without a name).
Basic syntax (anonymous)
const greet = function (name) {
return `Hello ${name}`;
};
// The function is invoked via the variable name
console.log(greet('Anthony')); // output: Hello Anthony
Named function expression (useful for debugging or recursion)
const factorial = function recursion(n) {
if (n <= 1) return 1;
return n * recursion(n - 1);
};
const fact = factorial(3);
console.log(fact); // output: 6
- The function is assigned to
factorial. - Inside the function body, the name
recursionrefers to the function itself, enabling recursion. - The name is not added to the surrounding scope; it exists only within the function.
Key differences between declaration and expression
| Aspect | Function Declaration | Function Expression |
|---|---|---|
| Evaluation | Treated as a statement; the engine creates the function during the compilation phase. | Evaluates to a value (a function object) at runtime. |
| Hoisting | Fully hoisted: both the name and the body are moved to the top of their scope, allowing calls before the declaration appears. | Not hoisted in the same way. The variable may be hoisted (depending on var, let, or const), but the assignment (the function object) occurs only when execution reaches that line. |
| Naming | Must have a name. | Can be anonymous or named (the name is local to the function). |
| Typical use | When you want a function available throughout its scope, regardless of where it is defined. | When you want a function as a value—e.g., passed as an argument, stored in data structures, or created conditionally. |
Basic idea of hoisting (very high level)
Hoisting means you can refer to a variable or function before its formal declaration appears in the source code.
During JavaScript’s compilation phase, function declarations and variable declarations are conceptually moved to the top of their containing scope. This allows early references, though the actual initialization (for variables) still happens at the original line.
Function Declaration Hoisting Example
// Works because the function declaration is hoisted
sayHello();
function sayHello() {
console.log('Hello!');
}
The engine reads the function’s name and body during compilation, so the call succeeds even though the declaration appears later in the source file.
Function Expression
It is a function stored in a variable; it isn’t hoisted in the same way as a function declaration. Only the variable declaration is hoisted, but the assignment stays in place.
// Throws TypeError: greet is not a function
greet();
var greet = function () {
console.log("Hello!");
};
The function greet is declared and assigned undefined. When you call it, you’re trying to invoke undefined().
Note: let and const are not hoisted, so you cannot access them before their declaration. Attempting to do so results in a ReferenceError.
When to Use Each Type
Choosing between a function declaration and a function expression depends on whether you need hoisting, how the function is used, and the desired scope and code style.
Use a Function Declaration When
- It’s a standalone statement that you need to access from anywhere in your code.
- You want hoisting so you can call it before its declaration appears.
- The
functionkeyword at the start makes it easy to spot, improving code structure for top‑level functions. - The function name is always available within its own scope, which is useful for recursion.
// Works because "add" is hoisted to the top level
console.log(add(7, 8));
function add(a, b) {
return a + b;
}
Use a Function Expression When
- You want to create a function as a value that is then assigned to a variable.
- You need to pass the function as an argument (e.g., callbacks).
- You want to invoke the function immediately and avoid polluting the global scope.
- You need conditional function definitions—defining logic based on certain conditions.
- Since they are not hoisted, the function only exists when the interpreter reaches the assignment, leading to more predictable or structured code flow.
// This will cause an error if called before the expression
// console.log(multiply(2, 3)); // ReferenceError: cannot access 'multiply' before initialization
const multiply = function (a, b) {
return a * b;
};
// Must be called after definition
console.log(multiply(2, 3)); // output: 6