JavaScript tutorials  /  JavaScript Function Expression
Chapter 9 · JavaScript

JavaScript Function Expression

A function expression in JavaScript is a way of defining a function and assigning it to a variable, property, or passing it as an argument, using the function keyword as part of an expression rather than a standalone statement. Unlike function declarations, function expressions are not hoisted with their definition, so the function can only be used after it has been assigned.

Think of a function expression like writing a recipe on a piece of paper and then putting that paper inside a labeled box (a variable). You can't use the recipe until you've actually placed it in the box. Only after the paper is inside the box can you take it out and use it. Similarly, a function expression only becomes usable after the line of code where it is assigned to a variable has run.

Consider a ride-sharing app like Uber or Ola that calculates fare estimates differently depending on the time of day — normal fare, peak-hour fare, or night-charge fare. Developers can store different fare calculation logic as function expressions assigned to variables like calculateNormalFare, calculatePeakFare, and calculateNightFare. Based on the current time, the app dynamically selects and invokes the correct function expression to calculate the estimated fare shown to the user before they confirm the ride. Since these are function expressions rather than declarations, they are cleanly scoped to where they are defined and don't clutter the global namespace.

Function expressions are important because they allow functions to be treated as values — they can be assigned to variables, stored in objects or arrays, passed as arguments to other functions, and returned from functions. This flexibility enables patterns like callbacks, higher-order functions, and module-like encapsulation using IIFEs. Since function expressions are not hoisted with their definitions, they also help developers write more predictable code by ensuring functions are defined before they are used.

  • Anonymous Function Expression: A function expression without a name, commonly assigned directly to a variable or passed as an argument, such as const greet = function() { return 'Hello'; };
  • Named Function Expression: A function expression that has a name, which is useful for recursion and debugging since the function name appears in stack traces, such as const factorial = function fact(n) { return n <= 1 ? 1 : n * fact(n - 1); };
  • Immediately Invoked Function Expression (IIFE): A function expression that is defined and executed immediately, often used to create a private scope, such as (function() { console.log('Executed immediately'); })();
  • Function Expression as Object Property: A function expression assigned as a value to an object's property, effectively creating a method, such as const user = { greet: function() { return 'Hi there'; } };
  • Function Expression Passed as Argument: A function expression passed directly into another function as an argument, commonly used in array methods and event handlers, such as array.forEach(function(item) { console.log(item); });
// Anonymous function expression const functionName = function(parameter1, parameter2) { // function body return result; }; // Named function expression const functionName = function namedFn(parameter1, parameter2) { return result; }; // Immediately Invoked Function Expression (IIFE) (function(parameter1, parameter2) { // function body })(argument1, argument2); // Calling a function expression functionName(argument1, argument2);
Suppose you're building a discount calculation module for an online store, and the discount logic should only be available within a specific part of your code without polluting the global scope, and it needs to be passed around as a value to different parts of your checkout flow depending on the type of promotion active. Using a regular function declaration would hoist the function globally and make it harder to control where and when it's available. How do you define a function that behaves like a flexible, scoped value that can be assigned, passed, and reassigned as needed?
Basic Anonymous Function Expression
Assigning an anonymous function expression to a variable and calling it.
JavaScript
const multiply = function(a, b) { return a * b; }; console.log(multiply(4, 5)); console.log(multiply(2, 10));
20 20
The function is defined without a name and assigned to the variable multiply. Since it's a function expression, it can only be called after this assignment line has executed. Both calls use the same reusable logic with different arguments.
Named Function Expression for Recursion
Using a named function expression to calculate factorial recursively, where the internal name helps with self-reference.
JavaScript
const factorial = function fact(n) { if (n <= 1) return 1; return n * fact(n - 1); }; console.log(factorial(5)); console.log(factorial(6));
120 720
The function expression is named fact internally, even though it's assigned to the variable factorial. This internal name fact allows the function to call itself recursively, which is useful because the internal name is only accessible within the function's own scope, keeping the global scope clean.
Immediately Invoked Function Expression (IIFE)
Creating a private scope using an IIFE to avoid polluting the global namespace, commonly used for module-like patterns.
JavaScript
const counterModule = (function() { let count = 0; return { increment: function() { count++; return count; }, reset: function() { count = 0; return count; } }; })(); console.log(counterModule.increment()); console.log(counterModule.increment()); console.log(counterModule.reset());
1 2 0
The IIFE runs immediately upon definition and returns an object containing increment and reset methods. The count variable is private and cannot be accessed directly from outside, but the returned methods form a closure that allows controlled access to modify it, demonstrating the module pattern.
Function Expression Passed as Callback
Passing a function expression directly as an argument to the setTimeout function and the array filter method.
JavaScript
const numbers = [10, 15, 20, 25, 30]; const evenNumbers = numbers.filter(function(num) { return num % 2 === 0; }); console.log(evenNumbers); setTimeout(function() { console.log('This runs after 1 second'); }, 1000);
[ 10, 20, 30 ] This runs after 1 second
An anonymous function expression is passed directly to filter() to keep only even numbers, and another anonymous function expression is passed to setTimeout() to run after a 1-second delay. Both demonstrate how function expressions are commonly used inline as arguments to other functions.
  • Trying to Call a Function Expression Before Its Definition: Since function expressions are not hoisted with their definitions, calling the variable before the line where the function is assigned results in a ReferenceError (for let/const) or undefined is not a function error (for var). For example, calling greet() before const greet = function() {...} throws an error, unlike function declarations which are fully hoisted.
  • Confusing Named Function Expressions with Declarations: Developers sometimes assume that a named function expression like const fn = function myFunc() {} makes myFunc available in the outer scope, but myFunc is only accessible within the function's own body, not outside it. Attempting to call myFunc() from outside the expression results in a ReferenceError.
  • Forgetting Parentheses in IIFE Syntax: A common syntax mistake when writing an IIFE is forgetting to wrap the function expression in parentheses before the invoking parentheses, such as writing function() {}() instead of (function() {})(), which results in a SyntaxError because JavaScript interprets it as an invalid function declaration followed by an unexpected token.
  • Losing Function Reference on Reassignment: Since function expressions assigned with let or var can be reassigned, accidentally reassigning the variable elsewhere in the code (e.g., myFunction = null) removes access to the original function, causing calls to myFunction() later to throw a TypeError, especially problematic in larger codebases with shared variable names.
  • Overusing IIFEs in Modern Code with ES Modules: Developers coming from older JavaScript codebases sometimes wrap every file in an IIFE to avoid global scope pollution, even when using modern ES modules (import/export), which already provide module-level scoping. This adds unnecessary complexity since ES modules make IIFEs redundant for scope isolation in most modern projects.
  • Use Named Function Expressions for Recursive Logic: When writing a function that needs to call itself, use a named function expression instead of relying on the outer variable name, since the outer variable could be reassigned elsewhere, breaking the recursion. The internal name remains stable and reliable within the function's own scope.
  • Prefer const Over var When Assigning Function Expressions: Always assign function expressions using const instead of var or let, unless reassignment is genuinely needed. This prevents accidental overwriting of the function reference and makes the code's intent clearer to other developers reading it.
  • Use IIFEs Only When Scope Isolation Is Genuinely Needed: Reserve IIFEs for legacy script-based environments without module support, or for specific patterns like the module pattern or avoiding global variable leaks in third-party embeddable scripts. In modern projects using ES modules or bundlers like Webpack and Vite, prefer regular module scoping instead.
  • Keep Function Expressions Readable When Used Inline: When passing function expressions as callback arguments (e.g., to map, filter, or event listeners), keep the logic short and readable. For longer or reusable logic, define the function expression separately with a descriptive name and pass the reference instead of writing a large inline function.
  • Leverage Function Expressions for Conditional Logic Assignment: Use function expressions when you need to assign different implementations of a function based on a condition, such as choosing between two calculation strategies at runtime, since function declarations cannot be conditionally reassigned as cleanly due to hoisting behavior and block-scoping quirks.
What is the key difference between a function declaration and a function expression regarding hoisting?
Function declarations are fully hoisted, meaning both the function name and its definition are available throughout the enclosing scope, even before the line where they appear in the code. Function expressions are only partially hoisted when using var (the variable is hoisted but not the assignment), or not accessible at all before initialization when using let or const, due to the temporal dead zone, meaning the function must be defined before it can be called.
What is the purpose of naming a function expression, and where is that name accessible?
Naming a function expression, such as const fn = function myFn() {}, primarily helps with recursion, since the function can refer to itself by its internal name, and it also improves debugging because the named function appears clearly in stack traces and browser dev tools. However, the internal name myFn is only accessible within the function's own body and is not accessible from the outer scope where the expression is assigned.
What is an IIFE and why was it commonly used before ES6 modules?
An IIFE, or Immediately Invoked Function Expression, is a function expression that executes immediately after being defined, typically wrapped in parentheses like (function() { ... })(). Before ES6 introduced native modules, IIFEs were commonly used to create private scopes, preventing variables from leaking into the global namespace and avoiding naming collisions between different scripts loaded on the same page.
Can a function expression be used before it's defined in the code? Explain why or why not.
No, a function expression cannot be reliably used before its definition. If declared with let or const, accessing it before the assignment line results in a ReferenceError due to the temporal dead zone. If declared with var, the variable itself is hoisted with an initial value of undefined, so calling it before assignment results in a TypeError stating that it is not a function, since only the variable declaration, not its function value, is hoisted.
How do function expressions enable the module pattern in JavaScript?
The module pattern uses an IIFE (a type of function expression) to create a private scope where variables and functions are hidden from the global scope by default. The IIFE returns an object exposing only the specific methods or properties intended to be public, while private variables remain accessible only through closures formed by the returned methods, effectively simulating encapsulation similar to private members in object-oriented programming.
Write an anonymous function expression assigned to a variable named square that takes a number and returns its square.
const square = function(num) { return num * num; }; console.log(square(6)); // 36
Create a named function expression called sumRecursive that calculates the sum of numbers from 1 to n using recursion.
const sumRecursive = function sum(n) { if (n <= 1) return n; return n + sum(n - 1); }; console.log(sumRecursive(5)); // 15
Write an IIFE that immediately calculates and logs the area of a rectangle with length 10 and width 5.
(function(length, width) { console.log(length * width); })(10, 5); // 50
Create a module pattern using an IIFE that maintains a private array of tasks, with methods addTask and getTasks exposed publicly.
const taskManager = (function() { let tasks = []; return { addTask: function(task) { tasks.push(task); return tasks; }, getTasks: function() { return tasks; } }; })(); taskManager.addTask('Learn JS'); taskManager.addTask('Build a project'); console.log(taskManager.getTasks()); // [ 'Learn JS', 'Build a project' ]
Write a function expression named processOrder that is passed as a callback to another function called handleCheckout, which calls it with an order amount and logs a confirmation message.
const processOrder = function(amount) { console.log(`Order processed for amount: $${amount}`); }; function handleCheckout(orderAmount, callback) { callback(orderAmount); } handleCheckout(150, processOrder); // 'Order processed for amount: $150'

Function expressions are a flexible way to define functions in JavaScript by assigning them to variables, object properties, or passing them directly as arguments. Unlike function declarations, they are not fully hoisted, meaning they must be defined before use. Function expressions can be anonymous, named, or immediately invoked (IIFE), and they play a crucial role in patterns like callbacks, closures, and module encapsulation. Understanding the distinction between function expressions and declarations, along with their scoping and hoisting behavior, is essential for writing predictable and maintainable JavaScript code.

© 2026 CompileX. Maintained by Aditya Kumar Sharma.