Course: JavaScript Intermediate
Lesson 3: Function Expressions
Level
Intermediate
Estimated Reading Time
10–15 minutes
Goal
By the end of this lesson, the learner will be able to:
- Store a function in a variable using a function expression
- Explain the difference between a function expression and a function declaration
- Use anonymous and named function expressions in realistic situations
Frontend Development Context
Function expressions are everywhere in frontend JavaScript. When you pass a function to addEventListener, setTimeout, or an array method like map, you are usually passing a function expression. The ability to store functions in variables and pass them around like values is fundamental to how JavaScript handles events, callbacks, and asynchronous code.
Understanding the difference between function expressions and function declarations also helps you understand hoisting behavior and why some functions are available immediately while others are not. As you move toward frameworks like React, you will write function components and event handlers almost exclusively as function expressions or arrow functions.
Explanation
A function declaration uses the function keyword at the start of a statement and gives the function a name. A function expression also uses the function keyword, but it appears on the right-hand side of an assignment — the function is stored as a value inside a variable.
The key difference in behavior is hoisting. Function declarations are fully hoisted, so you can call them before they appear in the file. Function expressions are not — the variable is hoisted (as undefined if using var, or in the temporal dead zone with let/const), but the function value is not assigned until that line runs.
A function expression can be anonymous — it has no name after the function keyword. Anonymous function expressions are common as callbacks passed directly to other functions. Named function expressions include a name after the function keyword; the name is only visible inside the function itself, which is useful for recursion and stack traces.
Because functions are values in JavaScript, a function expression can be stored in a variable, passed as an argument, returned from another function, or stored in an object. This flexibility is what makes JavaScript a functional-style language at its core.
Code Example
This example shows a function declaration, an anonymous function expression, and a named function expression, then demonstrates passing a function expression as a callback.
// Function declaration — hoisted, available anywhere in scope
function formatName(name) {
return name.trim().toUpperCase();
}
// Anonymous function expression — stored in a variable
const greetUser = function (name) {
return `Welcome, ${formatName(name)}!`;
};
// Named function expression — name is only visible inside the function
const factorial = function calculate(n) {
if (n <= 1) return 1;
return n * calculate(n - 1); // uses the internal name for recursion
};
console.log(greetUser(" alice ")); // "Welcome, ALICE!"
console.log(factorial(5)); // 120
// Passing a function expression directly as a callback
const scores = [42, 95, 78];
const passing = scores.filter(function (score) {
return score >= 75;
});
console.log(passing); // [95, 78]
Code Explanation
formatName is a function declaration. It is fully hoisted and could be called anywhere in the scope, even before this line appears in the file.
greetUser is an anonymous function expression. The function has no name of its own — it is just a value assigned to the variable greetUser. It can only be called after this assignment line runs.
factorial is a named function expression. The name calculate is only visible inside the function body, where it is used for recursion. Outside the function, you access it through the variable factorial. Named function expressions produce cleaner stack traces in error messages than anonymous ones.
The scores.filter(function(score) {...}) at the bottom passes an anonymous function expression directly as a callback. This is extremely common in JavaScript — array methods, event listeners, and timers all accept functions as arguments.
Pattern Highlights
✅ Positive Pattern: Use function expressions (or arrow functions) when passing functions as arguments or storing them in variables. This clearly communicates that the function is a value being used somewhere.
⚠️ Neutral Note: Named function expressions provide better stack traces and support recursion internally. They are slightly more verbose than anonymous expressions but easier to debug.
❌ Negative Pattern: Do not call a function expression before the line where it is assigned. Unlike declarations, expressions are not hoisted — you will get a TypeError or ReferenceError depending on how the variable was declared.
Common Mistakes
Mistake 1: Calling a function expression before it is assigned
Treating a function expression like a declaration and expecting it to be available early.
console.log(sayHello("world")); // TypeError: sayHello is not a function
var sayHello = function (name) {
return `Hello, ${name}!`;
};
var sayHello is hoisted and holds undefined until the assignment runs. Calling undefined as a function throws a TypeError. Move the call after the assignment.
Mistake 2: Forgetting that an anonymous function expression has no name for recursion
Trying to call an anonymous function by the variable name from inside itself in a way that may break.
const countDown = function (n) {
if (n <= 0) return;
console.log(n);
countDown(n - 1); // works, but reassigning countDown elsewhere would break this
};
If countDown is ever reassigned to a different value, the recursion breaks. A named function expression avoids this by using an internal name that cannot be reassigned.
Mistake 3: Confusing function expressions with object method shorthand
Writing a function expression as a property value when object shorthand is cleaner.
const user = {
greet: function () { // works but verbose
return "Hello!";
}
};
Modern JavaScript supports method shorthand: greet() { return "Hello!"; }. While the function expression version is not wrong, the shorthand is preferred inside object literals for clarity.
Quick Recap
- A function expression stores a function as a value in a variable rather than declaring it as a statement
- Function expressions are not hoisted — you cannot call them before the assignment line
- Anonymous function expressions have no internal name; named function expressions have a name visible only inside the function
- Functions as values can be passed as arguments, returned from functions, or stored in objects — this is central to JavaScript's design