Compile Ready
Module 5 · Functions

Function Expressions

Beginner9m read10m practice19m total
FunctionsExpressionsTDZClosures

Introduction

A function expression creates a function value as part of an expression. That value can be assigned to a variable, passed as an argument, returned from another function, or stored in an object.

The most common modern form is const fn = function (...) { ... }. The variable follows normal const or let rules, so the function value is not available until the assignment line executes.

Why This Matters

Function expressions are where functions start to feel like values. They explain callback-heavy JavaScript, decorators like once, named function expressions for recursion, and one of the most common output puzzles: declaration hoisting works, but a const function expression is in the temporal dead zone.

Theory

Expression, not declaration

A declaration creates a named binding directly. A function expression evaluates to a function object. The receiving variable or property determines how you access it.

FormHoisting behaviorTypical use
function run() {}Function body is available throughout scope.Named reusable operation.
const run = function () {}run is in TDZ until initialized.Function value assigned to a constant.
const run = function namedRun() {}Outer name is run; inner name helps recursion/debugging.Recursion and better stack traces.

A function expression can be anonymous or named. Named expressions are underrated: the inner name is available inside the function body, which helps recursion and stack traces without leaking a second name into the outer scope.

If a function expression is assigned to const or let, the binding exists but cannot be read before initialization. If assigned to var, the variable is hoisted as undefined, so calling it early usually throws TypeError because undefined is not callable.

Because function expressions are values, they are ideal for wrappers. A wrapper can keep private variables in a closure and return a new function that controls how the original function is called. This is how utilities such as once, memoize, debounce, and throttle are built.

Visual Diagrams

Function expression initialization
enter scope
  makeLabel exists but is uninitialized  <- TDZ

execute assignment
  makeLabel -> function object

later
  makeLabel('Ada') calls the stored function value

The variable follows `const` or `let` timing; the function object is created when the expression runs.

Code Examples

Named function expression for recursion

The inner name fact is available inside the function, even though callers use the outer variable factorial.

Loading…

Expressions can be selected at runtime

Because functions are values, a branch can choose which implementation to store.

Loading…

Playground

Loading editor…
Console

Press Run to execute the code and see output here.

Output Prediction

Predict the output #1

javascript
1console.log(declared());
2
3function declared() {
4 return 'declaration ready';
5}
6
7try {
8 console.log(expressed());
9} catch (error) {
10 console.log(error.name);
11}
12
13const expressed = function () {
14 return 'expression ready';
15};
16
17console.log(expressed());

Coding Exercises

Implement once as a function expression

Medium

Implement once(fn) using a function expression. It should return a wrapper that calls fn only the first time. Later calls should return the first result without calling fn again. Preserve the caller's this and arguments.

Interview Questions

1How does a function expression assigned to `const` differ from a function declaration?

A declaration is hoisted with its function body and can be called before its source line. A const function expression follows lexical-binding rules: the name is in the temporal dead zone until the assignment executes. After initialization, both refer to callable function objects, but their creation timing and readability tradeoffs differ.

Asked at:GoogleMetaAmazon

Follow-ups

  • What happens if the expression is assigned to `var` instead?
  • Why might you use a named function expression?
2Why are function expressions useful for wrappers like `once` or `memoize`?

They are values that can be returned from other functions. The returned wrapper closes over private state such as a cache, a called flag, or timing metadata, while exposing a normal callable API to the outside.

Quiz

1. What happens when you call a `const` function expression before the assignment line executes?

Summary

  • A function expression evaluates to a function value.
  • `const` and `let` function expressions are not callable before initialization because of the TDZ.
  • Named function expressions improve recursion and stack traces without creating a second outer binding.
  • Expressions are ideal for wrappers that close over private state.

Cheat Sheet

Syntax: const fn = function (params) { ... };.

Timing: variable rules apply. const and let are TDZ before initialization; var is undefined before assignment.

Named expression: const f = function inner() { inner(); }; helps recursion/debugging.

Power move: return function expressions to build wrappers like once, memoize, debounce, and throttle.