PROGRAMMING-CONCEPTS

Closure: Definition, Purpose, and Examples

A closure is a function that retains access to variables from the scope where it was created, even after that scope has finished executing. In other words, the function “remembers” its surroundings.

Closures are used across many languages to preserve state, customize behavior, and build flexible, composable logic. They show up in everyday programming, especially when working with callbacks, event handlers, and functional programming patterns.


What a Closure Really Is

A closure forms when:

  1. A function is defined inside another function
  2. The inner function uses variables from the outer function
  3. The outer function returns the inner function (or passes it elsewhere)

The key idea:

The inner function keeps access to the outer function’s variables, even after the outer function is done executing.

This ability to “carry” context makes closures powerful for creating dynamic and stateful behavior without relying on classes or global variables.


Closures in JavaScript and TypeScript

JavaScript uses closures everywhere — in event handlers, timers, React components, and countless utilities.

Simple closure example

function createCounter() {
  let count = 0; // captured variable

  return function () {
    count++;
    return count;
  };
}

const counter = createCounter();

counter(); // 1
counter(); // 2

Why this works:

count lives inside createCounter(), but the returned function keeps a reference to it. The outer function finishes, but count stays alive through the closure.

Customizing behavior with closures

function multiplier(factor) {
  return function (value) {
    return value * factor;
  };
}

const double = multiplier(2);
const triple = multiplier(3);

double(4); // 8
triple(4); // 12

Each closure stores its own factor, creating reusable functions with different behavior.

Closure in a TypeScript example

function addSuffix(suffix: string) {
  return function (word: string): string {
    return word + suffix;
  };
}

const addLy = addSuffix("ly");
addLy("quick"); // "quickly"

Types help enforce what each closure returns and captures.


Closures in Python

Python closures follow the same pattern using nested functions.

def make_adder(x):
    def add(y):
        return x + y
    return add

add5 = make_adder(5)
add5(10)  # 15

x remains accessible because add() carries it along.

Mutating closed-over values

Python requires the nonlocal keyword when modifying a captured variable.

def running_total():
    total = 0

    def add(amount):
        nonlocal total  # allows modification
        total += amount
        return total

    return add

counter = running_total()
counter(5)  # 5
counter(3)  # 8

Closures become a lightweight way to track internal state.


Closures in Swift

Swift closures are similar to anonymous functions or lambdas.

Basic closure capturing a value

func makeIncrementer(amount: Int) -> () -> Int {
    var total = 0

    let incrementer = {
        total += amount
        return total
    }

    return incrementer
}

let incrementByTwo = makeIncrementer(amount: 2)
incrementByTwo() // 2
incrementByTwo() // 4

Swift captures variables by reference, letting closures modify the original values.


When to Use Closures

Closures are helpful wherever you need functions that carry context or create custom behavior.

1. Preserving state without classes

Instead of storing counters or values globally, closures encapsulate state neatly inside a function.

2. Creating function factories

You can build specialized functions by capturing configuration values, like multipliers, formatters, or validators.

3. Callbacks and event handlers

Closures provide access to surrounding variables without needing to pass everything explicitly.

4. Functional programming patterns

Mapping, filtering, reducing, currying, and composition often rely on closures.

5. React components

Even though React hooks rely on closures internally, the pattern is invisible to most beginners — but it’s closures that preserve state across re-renders.


Examples of Closures in Real Code

Example 1: Event handlers (JavaScript)

function setupButton(message) {
  const button = document.querySelector("button");

  button.addEventListener("click", () => {
    console.log(message);
  });
}

setupButton("Welcome!");

The arrow function remembers message when the event happens later.


Example 2: Creating reusable formatting functions (Python)

def currency_formatter(prefix):
    def format(amount):
        return f"{prefix}{amount:.2f}"
    return format

usd = currency_formatter("$")
usd(19.99)  # "$19.99"

This pattern appears constantly in real applications — a function is created, customized, and reused.


Example 3: Delayed execution (JavaScript)

function later(msg) {
  return () => console.log("Later:", msg);
}

const task = later("Save completed");

setTimeout(task, 1000);

task still knows what msg was, even though later() has already executed.


Closures vs Regular Functions

Regular functions run with the variables available at the moment they execute.

Closures run with the variables available at the moment they were created.

This distinction explains why closures feel “stateful”:

  • They keep data alive
  • They remember old values
  • They customize behavior

Closures make functions behave more like objects: they can hold internal state without being classes.


Common Mistakes with Closures

1. Expecting fresh values each time

Because closures remember state, they might preserve a value longer than expected.

2. Capturing variables inside loops

In JavaScript, loops once caused surprising behavior because closures captured references, not values. Modern JS solves most of this with let instead of var.

3. Using closures when a simple function is enough

Closures add power but also complexity — sometimes a plain function is clearer.

4. Accidental memory retention

Keeping references alive longer than necessary can cause memory growth in long-running applications.


Summary

A closure is a function that retains access to the variables from the environment where it was created. This lets the function preserve state, customize behavior, and react to context long after the original scope has finished. JavaScript, TypeScript, Python, and Swift all rely on closures for callbacks, function factories, and flexible programming patterns. Closures keep code modular, expressive, and powerful — especially when building dynamic applications.

Learn to Code for Free
Start learning now
button icon
To advance beyond this tutorial and learn to code by doing, try the interactive experience of Mimo. Whether you're starting from scratch or brushing up your coding skills, Mimo helps you take your coding journey above and beyond.

Sign up or download Mimo from the App Store or Google Play to enhance your programming skills and prepare for a career in tech.

Reach your coding goals faster