JS Function Declarations vs Expressions: Differences & Use Cases
Discover key differences between JavaScript function declarations and function expressions. Explore hoisting, pros, cons, var function() {} vs function name() {}, and real-world use cases for better coding.
What are the differences between function declarations and function expressions in JavaScript, including their pros, cons, and use cases? Specifically, what are the reasons for using var functionOne = function() {} versus function functionTwo() {}, and what can be done with one method that can’t be done with the other?
JavaScript function declarations like function functionTwo() {} get hoisted to the top of their scope, so you can call them before they’re physically written in code. Function expressions, such as var functionOne = function() {}, aren’t hoisted that way—only the variable is, leaving the function undefined until execution hits the assignment. Declarations suit reusable utilities anywhere in scope; expressions excel at callbacks, one-offs, and avoiding namespace clutter.
Contents
- JavaScript Function Declarations
- Function Expressions in JavaScript
- Key Differences Between Them
- Pros and Cons of Function Declarations
- Pros and Cons of Function Expressions
- Real-World Use Cases
- Unique Capabilities: What One Does That the Other Can’t
- Sources
- Conclusion
JavaScript Function Declarations
Picture this: you’re midway through a script, and bam—you need to invoke a function that’s defined lines later. No sweat with declarations. A JavaScript function declaration looks like function functionTwo() { console.log('Hoisted!'); }. The JS engine reads the entire script first, hoists the whole thing—name and body—to the top of its scope during compilation.
Why does this matter? Hoisting means functionTwo(); works even if called before the line where it’s written. FreeCodeCamp nails it: declarations load into memory before execution starts. Same goes for MDN docs—they emphasize how this makes functions available throughout the block, function, or global scope.
But here’s a quirk. Nest them in an if-statement? Like if (true) { function sneaky() {} }. Old browsers hoist it anyway, potentially to the outer scope. Messy, right? Modern strict mode helps, but it trips up beginners.
// This works—hoisting in action
sayHello(); // "Hello!"
function sayHello() {
console.log("Hello!");
}
Declarations always have a name, aiding recursion or debugging stacks. They’re your go-to for core app logic.
Function Expressions in JavaScript
Flip the script. Function expressions assign a function to a variable: var functionOne = function() { console.log('Not hoisted'); };. The variable functionOne hoists (as undefined), but the assignment waits until runtime. Call it early? Error city: TypeError: functionOne is not a function.
JavaScript.info breaks it down: expressions arise in assignment contexts, not standalone statements. GeeksforGeeks adds they can be anonymous—no name required—perfect for quick jobs.
You can name them too: var namedOne = function inner() {}; (name’s just for internal use, like recursion). And don’t sleep on arrow functions—they’re expressions by nature: const arrow = () => {};.
// This fails
greet(); // TypeError!
var greet = function() {
console.log("Hi there!");
};
Expressions shine in dynamic spots. Ever passed a sorter to array.sort()? That’s an expression, often anonymous.
Key Differences Between Them
| Aspect | Function Declaration | Function Expression |
|---|---|---|
| Syntax | function name() {} |
var/const/let name = function() {} |
| Hoisting | Full hoist (name + body) | Variable hoists as undefined |
| Timing | Compile phase | Runtime assignment |
| Naming | Always named | Optional (anonymous OK) |
| Scope | Block/function/global | Determined by variable (let/const block-scoped) |
Stack Overflow consensus: hoisting’s the star difference. Declarations process pre-execution; expressions wait. Sentry.io clarifies var functionName = function() {} evaluates line-by-line.
What about const or let? Same expression rules apply—safer scoping than var. No hoisting surprises there.
Confused on conditionals? Declarations hoist regardless; expressions let you pick based on logic. Game-changer.
Pros and Cons of Function Declarations
Pros:
- Call anytime in scope. Freedom!
- Named for stack traces—debugging dreams.
- Reusable globally without reassignment fuss.
Cons:
- Pollutes scope. Global
utils()everywhere? Recipe for conflicts. - Conditional hoisting weirdness in legacy browsers.
- Can’t assign conditionally without hacks.
Gomakethings warns of namespace bloat. Still, for bootstrapping apps, they’re clutch.
Pros and Cons of Function Expressions
Pros:
- Scoped tight—
constkeeps 'em local. - Anonymous for throwaways, no name pollution.
- Conditional definition:
let fn = condition ? fnA : fnB;. - IIFEs:
(function() { /* private world */ })();.
Cons:
- Must define before use. Order matters.
- Anonymous? Stack traces say “anonymous”—hunt time.
varhoists undefined—gotcha for newbies.
Readwriteexercise loves their intuitive flow: define, then call. W3tutorials echoes flexibility.
Real-World Use Cases
Declarations rock for:
- Main modules: event handlers, APIs.
- Libraries:
function fetchData() {}—use early. - Recursion: self-reference easy.
Like function factorial(n) { return n ? n * factorial(n-1) : 1; }.
Expressions fit:
- Callbacks:
fetch(url).then(function(data) { ... });. - Modules: IIFEs for privates pre-ES6.
- Higher-order:
array.map(function(item) { return item * 2; });. - Conditionals: API mocks in tests.
FreeCodeCamp’s second piece suggests declarations for globals, expressions for args. Spot on.
Modern twist? Arrows as expressions: const handler = (e) => e.preventDefault();. Concise.
Unique Capabilities: What One Does That the Other Can’t
Declarations: Invoke before code line. Pure magic, but risky in blocks. Can’t define conditionally without duplication.
Expressions: True conditionals. if (isDev) { var mock = function() { return fakeData; }; }. No hoist leaks. IIFEs create instant scopes—var result = (function() { var private = 42; return private * 2; })();. Declarations can’t self-invoke that slick.
Pass anonymously: setTimeout(function() { alert('Tick!'); }, 1000);. No extra name. Devdotun highlights control.
Bottom line: Use function functionTwo() {} for always-available helpers. var functionOne = function() {} for flexible, scoped power.
Sources
- FreeCodeCamp: Function Declaration vs Function Expression
- MDN: function expression
- FreeCodeCamp: When to use declarations vs expressions
- JavaScript.info: Function expressions
- GeeksforGeeks: Difference between declaration and expression
- Stack Overflow: Expression vs declaration
- Sentry.io: var function vs function
- Gomakethings: Expressions vs declarations
- Readwriteexercise: Declarations vs expressions
- W3tutorials: var functionName vs function
- Devdotun: Understanding differences
Conclusion
Master function declarations for hoisted reliability in core logic, but lean on function expressions for modern scoping, callbacks, and conditionals—especially with const or arrows. The var functionOne = function() {} style gives you runtime control and IIFE magic that declarations can’t match without workarounds, while function functionTwo() {} delivers anytime access. Pick based on needs: avoid global mess, embrace flexibility, and your JS will flow smoother. Test in console—hoisting hits different once you see it.