Academic Block

JavaScript Function Expressions Get Certified

A function expression defines a function as part of a larger expression, typically by assigning it to a variable. Unlike a function declaration, a function expression is not hoisted the same way, and it doesn’t need a name.

Function expressions are extremely common in JavaScript, especially for passing functions around as values — for example, as callbacks.

In this lesson, you will learn how to write function expressions, how they differ from function declarations, and how they are used in everyday JavaScript code.

Basic Function Expression Syntax

A function expression is created by assigning an anonymous (or named) function to a variable.

What this code does: A function expression creates a function and stores it in a variable. Here greet holds an anonymous function. Calling greet() runs that function and prints the message.

const greet = function () {
    console.log("Hello, Michael!");
};
greet();

Here, the function has no name of its own — it’s called an anonymous function. The variable greet is what allows us to call it later.

Function Expressions With Parameters

Just like function declarations, function expressions can accept parameters and return values.

What this code does: Function expressions can take parameters and return values just like declarations. addNumbers receives 5 and 10, returns their sum, and the result is printed.

const addNumbers = function (a, b) {
    return a + b;
};
console.log(addNumbers(5, 10));

Named Function Expressions

A function expression can also have its own name. This name is mainly useful for debugging (it appears in stack traces) and for allowing the function to refer to itself, such as in recursion.

What this code does: A named function expression has an internal name for recursion or clearer stack traces. calculateFactorial calls itself until it reaches 1. The factorial of 5 (120) is printed.

const factorial = function calculateFactorial(n) {
    if (n <= 1) {
        return 1;
    }
    return n * calculateFactorial(n - 1);
};
console.log(factorial(5));

Notice that the name calculateFactorial is only accessible from inside the function itself — outside the function, you must still refer to it through the variable factorial.

Function Expressions Are Not Hoisted the Same Way

Unlike function declarations, a function expression cannot be called before it is defined. The variable holding the function is hoisted, but its value (the function itself) is not assigned until that line of code actually runs.

What this code does: Unlike function declarations, function expressions are not hoisted. Calling square before it is defined causes an error. The catch block prints that error message.

try {
    square(5);
} catch (err) {
    console.log("Error:", err.message);
}
const square = function (number) {
    return number * number;
};

Since square was declared with const, trying to use it before the declaration line throws a ReferenceError, because it is still in the temporal dead zone at that point.

Passing Functions as Arguments (Callbacks)

Because functions are values in JavaScript, a function expression can be passed directly as an argument to another function. A function passed this way is often called a callback.

What this code does: A classic callback pattern: pass a function expression as an argument. processUser runs its logic, then calls the callback with the name, which prints the welcome message.

function processUser(name, callback) {
    console.log("Processing user:", name);
    callback(name);
}
processUser("Michael", function (name) {
    console.log("Welcome, " + name + "!");
});

Instead of assigning the function expression to a variable first, it is written directly where it’s needed. This is a very common pattern with array methods and event handlers.

What this code does: Array methods like map() accept a function expression as a callback. Each number is doubled, producing a new array that is then printed.

const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(function (number) {
    return number * 2;
});
console.log(doubled);

Immediately Invoked Function Expressions (IIFE)

A function expression can be called immediately after it’s defined by wrapping it in parentheses and calling it right away. This pattern is known as an Immediately Invoked Function Expression, or IIFE.

What this code does: An IIFE (Immediately Invoked Function Expression) defines a function and runs it right away. The extra parentheses make the function an expression, and the final () calls it immediately.

(function () {
    console.log("This runs immediately!");
})();

IIFEs are often used to create a private scope, so that variables defined inside don’t leak into the surrounding code.

What this code does: Variables declared inside an IIFE stay private to that scope. secretValue is accessible inside the IIFE but causes a ReferenceError outside it.

(function () {
    let secretValue = 42;
    console.log("Inside the IIFE:", secretValue);
})();
try {
    console.log(secretValue);
} catch (err) {
    console.log("Error:", err.message);
}

Function Expressions as Object Methods

A function expression is often used directly as a property value in an object, creating what is called a method.

What this code does: Object methods are often written as function expressions. calculator.add and calculator.subtract are called and their results are printed.

const calculator = {
    add: function (a, b) {
        return a + b;
    },
    subtract: function (a, b) {
        return a - b;
    }
};
console.log(calculator.add(10, 5));
console.log(calculator.subtract(10, 5));

Function Declarations vs. Function Expressions

Aspect Function Declaration Function Expression
Syntax function name() {} const name = function () {}
Hoisting Fully hoisted (usable before defined) Not usable before the assignment line
Name required? Yes No (can be anonymous)
Common use case General-purpose named functions Callbacks, methods, IIFEs

Practical Example

Let’s use a function expression as a callback to filter an array of numbers.

What this code does: Store a function expression in a variable and reuse it as a callback. isEven is passed to filter(), which keeps only the even numbers from the list.

const numbers = [3, 8, 15, 22, 6, 40];
const isEven = function (number) {
    return number % 2 === 0;
};
const evenNumbers = numbers.filter(isEven);
console.log(evenNumbers);

Storing the function expression in isEven first makes the code more readable, but it could also be written directly inline as an anonymous function.

Common Mistakes With Function Expressions

  • Trying to call a function expression before the line where it’s defined, expecting hoisting to work like it does with function declarations.
  • Forgetting the semicolon after a function expression assigned to a variable.
  • Forgetting to wrap an IIFE’s function in parentheses, resulting in a syntax error.
  • Assuming an anonymous function expression has a usable name for recursion, when only named function expressions can refer to themselves this way.
  • Overusing IIFEs in modern code where ES6 modules already provide proper scoping.

Best Practices for Function Expressions

  • Use const when assigning a function expression to a variable, unless you have a specific reason to reassign it.
  • Give a function expression a name when it will appear in stack traces or needs to reference itself recursively.
  • Use function expressions (or arrow functions) for callbacks passed to methods like map(), filter(), and forEach().
  • Prefer named, reusable function expressions over duplicating the same anonymous function in multiple places.
  • Consider arrow function syntax as a more concise alternative for simple function expressions.

Quick Summary

  • A function expression defines a function as part of an expression, usually by assigning it to a variable.
  • Function expressions can be anonymous or named.
  • Unlike function declarations, function expressions cannot be used before the line where they are defined.
  • Function expressions are commonly used as callbacks and object methods.
  • An IIFE is a function expression that runs immediately after being defined.
  • Because functions are values, function expressions can be passed around, stored, and returned just like any other value.

Try It Yourself

Modify the code below. Try changing the function expression’s logic, or passing it into a different array method like filter() or forEach().

What this code does: Practice example: change the mapping logic or try filter() / forEach(), then click Test My Code to see the new result.

const numbers = [1, 2, 3, 4, 5];
const squared = numbers.map(function (number) {
    return number * number;
});
console.log(squared);
Tip: If you’re not sure whether you need a function declaration or a function expression, ask yourself whether you need to call the function before it’s defined in the file. If not, a function expression (or arrow function) works just as well and is often the more common style for callbacks.

Understanding function expressions is essential before moving on to arrow functions, closures, and more advanced JavaScript concepts.

🧪 Test Your JavaScript Code

Edit the code on the left and click “Run Code” to see the console output on the right.

📝 JavaScript Code
👁 Console Output

Click “Run Code” to see the output here.

Ctrl + Enter to run code Esc to close