FSM Full Stack Masterclass
Platform under construction
JavaScript course badge

Functions & Scope

Intermediate

Closures

A closure happens when a function remembers variables from the scope where it was created, even after that outer function has finished.

function createCounter() {
  let count = 0;

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

const next = createCounter();
console.log(next());

Functions & Scope

Closures let functions keep private state.

A closure is created when an inner function uses variables from an outer scope. The inner function keeps access to those variables later.

Closures are not rare or advanced magic. They appear in event handlers, timers, factory functions, modules, callbacks and stateful utilities.

The power of closures is private memory. The risk is accidental memory or stale values when a function keeps more data alive than expected.

Outer scope

The variables available where the function is created.

Inner function

The function that keeps access to those variables.

Private state

State hidden from direct outside access.

Factory function

A function that returns configured behavior.

Examples

Functions become readable when input, output and scope are visible.

Private state through a factory

function createCounter() {
  let count = 0;

  return {
    next() {
      count += 1;
      return count;
    }
  };
}

Global state for one local job

let count = 0;

function next() {
  count += 1;
  return count;
}

// Any code can now change count.

Code patterns

Reusable examples for quick reference.

These examples focus on syntax you will actually look up later: declarations, callbacks, returns, closures and context handling. Use the small patterns first, then study the deeper explanation.

Counter closure

Keep state without a global variable.

function createCounter() {
  let count = 0;

  return () => {
    count += 1;
    return count;
  };
}

Formatter factory

Create a configured function.

function createPrefixer(prefix) {
  return (value) => `${prefix}: ${value}`;
}

const status = createPrefixer("Status");
console.log(status("ready"));

Private module state

Expose methods while keeping data private.

function createStore() {
  const items = [];

  return {
    add(item) { items.push(item); },
    count() { return items.length; }
  };
}

Event handler remembers state

A handler can keep local state across clicks.

function attachCounter(button, output) {
  let count = 0;

  button.addEventListener("click", () => {
    count += 1;
    output.textContent = count;
  });
}

Rules that matter

Keep behavior small, named and testable.

Functions are where JavaScript stops being a list of statements and becomes a system. Scope decides what each function can see, while return values and parameters decide how functions communicate.

Closures remember scope

The inner function keeps access to outer variables.

Use closures for private state

Factory functions can hide implementation details.

Avoid accidental retention

Do not close over large data unless it is needed.

Prefer clear factory names

createCounter and createStore communicate stateful behavior.

Watch loops and callbacks

let gives each loop iteration its own binding.

Do not overcomplicate simple state

Closures are useful, but not every variable needs privacy machinery.

Production thinking

Good functions reduce the amount of code you must hold in your head.

Why does this matter?

Closures explain why callbacks can remember values. Once that clicks, many JavaScript patterns become much less mysterious.

Accessibility

Stateful UI helpers can use closures to keep state local while updating accessible text and attributes.

Production note

Production closures should keep state private without hiding too much behavior or retaining unnecessary memory.

SEO note

Rendering factories can keep configuration local, but output should still be deterministic and testable.

Live code lab

Change the HTML, CSS or JavaScript and run the result.

The preview runs inside an isolated iframe. The JavaScript is placed inside the HTML editor for now, so every example stays together and remains easy to understand.

Mini assignment

Try this now.

  • Create a second independent counter.
  • Add a reset method by returning an object instead of one function.
  • Move count outside createCounter and compare the behavior.

Practice assignment

Do this before moving to the next topic.

  1. Write a function that returns another function.
  2. Use a closure to remember one value.
  3. Create two counters and prove they do not share state.

Try it yourself

Create a private counter

Live preview

Self-check

Before you continue, prove that you understand Closures.

Intermediate

Functions only become useful when you can explain what goes in, what comes out and which scope the function can see.

  1. Can you explain what a closure remembers?
  2. Can you explain why closures create private state?
  3. Can you explain what a factory function is?
  4. Can you explain how event handlers use closures?
  5. Can you explain one memory risk with closures?

Senior audit upgrade

Extra production context for Closures.

Closure model

A closure is not magic. An inner function keeps access to variables from the outer function after the outer function has returned.

outer function creates variable
  -> inner function uses it
  -> inner function is returned
  -> variable stays reachable through the closure