Closures and Private State

Introduction: Why Closures Matter in Functional Programming

Welcome to the first lesson of our course on Functional Programming Patterns in JavaScript. As we begin our journey together, it is important to understand that functional programming is not just about using functions; it is about how we control data and behavior. One of the biggest challenges in software development is managing state — the data that changes over time. If any part of a program can change a variable, your code becomes hard to predict and even harder to debug.

This is where closures come in. In functional programming, we use closures to create a sense of order. They allow us to hide data so it cannot be changed accidentally by other parts of the program. They also help us build flexible "factories" that create specialized functions for us. By mastering closures, you are learning the fundamental block that makes many other advanced patterns possible.

What Is a Closure?

In JavaScript, functions are created with access to their lexical scope. A closure is what we call this ability of a function to "remember" and access variables from the scope where it was defined. While every function is technically linked to its scope, we usually notice a closure most clearly when an inner function keeps using variables from an outer function's scope after that outer function has finished executing.

This behavior is powerful because it allows a function to carry data around with it. Usually, when a function finishes running, all its local variables are wiped from memory. However, if an inner function is still using those variables, JavaScript keeps them alive. This "persistent memory" is what we refer to when we talk about a closure capturing a variable from its enclosing scope.

Creating Private State with Closures

One of the most common ways to use closures is to create private state. In many programming styles, you might use a global variable to keep track of a value, but that is risky because any piece of code could change it. With a closure, we can hide a variable so that only specific functions can touch it.

Let's look at a practical example called makeCounter.

"use strict";

function makeCounter(initial = 0) {
  let count = initial; // private — only the returned functions can touch it
  return {
    increment: () => ++count,
    decrement: () => --count,
    value:     () => count,
  };
}

const c = makeCounter(10);
c.increment();
c.increment();
c.decrement();
console.log("value:", c.value()); 

In this code, the count variable is defined inside makeCounter. When we call makeCounter(10), it returns an object containing three functions: increment, decrement, and value. Because these functions were defined inside makeCounter, they form a closure around the count variable.

The variable count is truly private. If you try to access c.count directly, you will get undefined because it is not a property of the object; it lives only inside the closure. The only way to change or see the value is through the methods we provided. When we run this specific example, the output shows the result of our operations on that hidden variable.

value: 11
Sign up

Join the 1M+ learners on CodeSignal

Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal