Function Declarations vs Function Expressions in JavaScript
Function declarations and expressions look similar but behave differently. Here is the difference and when to use each.
Function Declarations vs Function Expressions in JavaScript
There are two main ways to define a function in JavaScript. They look similar but hoist differently and have different best-use cases.
Function Declaration
function greet(name) { return `Hello, ${name}`; }
- Hoisted with the full body. Can be called before the declaration line.
- The name is bound in the enclosing scope.
Function Expression
const greet = function (name) { return `Hello, ${name}`; };
- The function is assigned to a variable. The variable is hoisted (
varasundefined,let/constin TDZ), not the function. - Must be declared before calling.
Named Function Expression
const greet = function sayHi(name) { return `Hello, ${name}`; };
The internal name sayHi is only visible inside the function (useful for recursion and better stack traces). Outside, you must use greet.
Arrow Function (Always an Expression)
const greet = (name) => `Hello, ${name}`;
Arrows are always expressions. They do not have their own this or arguments.
Behavioral Differences
| Feature | Declaration | Expression |
|---|---|---|
| Hoisting | Full body | Variable only |
| Calling before line | Works | Error (TypeError or ReferenceError) |
| Use in conditionals/loops | Tricky (block-scoped in ES6) | Safe with const |
| Recursion | Use own name | Use internal name or outer variable |
When to Use Each
- Function declarations: for top-level helpers you want callable from anywhere in the file.
- Function expressions (with
const): for everything else, especially when you want predictable declaration-before-use behavior. - Arrow functions: for short callbacks and when you want lexical
this.
Best Practice
For consistency and to avoid hoisting surprises, many teams default to const arrow functions everywhere and only use function declarations when hoisting is genuinely needed.
The Takeaway
Function declarations are hoisted with their full body and can be called early. Function expressions are assigned to variables and must be declared before use. Use declarations for top-level helpers and const expressions (often arrows) for the rest.
A function declaration is hoisted with its full body, so it can be called before its line. A function expression is assigned to a variable, which is hoisted (undefined with var, TDZ with let/const) but the function body is only assigned at the line.
No. With var, calling it early throws TypeError because the variable is undefined. With let or const, it throws ReferenceError because the variable is in the Temporal Dead Zone.
A function expression with an internal name, like const greet = function sayHi() {}. The internal name is only visible inside the function, useful for recursion and better stack traces. Outside, you use the variable name.
Use declarations for top-level helpers you want callable from anywhere. Use const function expressions (often arrows) for everything else, to enforce declare-before-use and avoid hoisting surprises.
Always an expression. Arrow functions are always assigned to a variable. They are hoisted as variables, not as functions, and they do not have their own this or arguments.
Ready to master React completely?
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.
Master React
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course.

