Keep Access to an Outer Binding

Keep Access to an Outer Binding

A closure is a function together with access to its surrounding lexical bindings. A school rule factory can return a function that remembers a particular threshold after the outer call returns.

Before this topic, review Understand Declarations Before Execution if its terms are unfamiliar.

What you’ll learn

  • Explain keep access to an outer binding through the school example.
  • Trace the shown operations and distinguish their result from displayed output.
  • Make the practice change and explain its consequence: The returned function now compares marks against its retained threshold of 75.

Work through the school example

This is JavaScript using language features and the host console. Read the initial values, then follow each operation to its displayed result. A declaration names a value, a function call performs an operation, and console.log displays its arguments.

JavaScript · school.js · complete example

function rule(threshold) {
  return (mark) => mark >= threshold;
}
const passed = rule(50);
console.log(passed(72));

Expected output

true
Run in JavaScript compiler →

A rule retains its threshold

JavaScript · source for this model

function rule(threshold) {
  return (mark) => mark >= threshold;
}
const passed = rule(50);
console.log(passed(72));

This diagram follows the supplied example. It is an explanatory model, not a JavaScript engine or a timing guarantee.

A rule retains its threshold

  1. Call the factory

    rule receives threshold 50.

    50
  2. Return the function

    The returned function retains access to the threshold binding.

    passed → threshold
  3. Call the result

    passed receives 72 and compares it against 50.

    true
Follow the relationships and values in the example.

What is a Closure in JavaScript?

A closure in JavaScript is a powerful concept that allows an inner function to access the variables of its outer function, even after the outer function has finished executing. This behavior is made possible through JavaScript's lexical scoping rules.

Understanding Lexical Scope

Lexical scope means that a function's ability to access variables is determined by its position in the source code. In other words, inner functions have access to the scope in which they were defined—not necessarily the scope from which they are called.

function outer() {
    let outerVar = "I am from outer";

    function inner() {
        console.log(outerVar);
    }

    return inner;
}

const closureFn = outer();
closureFn();
I am from outer

How Closures Work

When outer() is called, it returns the inner function. Even though outer() has finished execution, its variable outerVar is still accessible to inner()—this is the essence of a closure.

Closures Retain State

Closures can maintain their own private state because they retain access to the variables in their lexical scope.

function counter() {
    let count = 0;

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

const increment = counter();
console.log(increment()); // 1
console.log(increment()); // 2
console.log(increment()); // 3
1
2
3

Each time increment() is called, it accesses and modifies the same count variable inside counter(). That variable is preserved due to closure.

Real-World Use Case: Data Privacy

Closures are useful when you want to encapsulate data and prevent it from being accessed directly.

function secretHolder(secret) {
    return {
        getSecret: function() {
            return secret;
        },
        changeSecret: function(newSecret) {
            secret = newSecret;
        }
    };
}

const obj = secretHolder("hidden123");
console.log(obj.getSecret()); // hidden123
obj.changeSecret("exposed456");
console.log(obj.getSecret()); // exposed456
hidden123
exposed456

The variable secret is not accessible from outside the function—it’s only accessible via the closure methods.

Closures Inside Loops – A Common Pitfall

Using closures in loops often leads to unexpected behavior. Let’s see why:

for (var i = 0; i < 3; i++) {
    setTimeout(function() {
        console.log(i);
    }, 1000);
}
3
3
3

Because var is function-scoped, the variable i retains its final value of 3 in each closure. To fix this, use let or an IIFE:

Fix using let:

for (let i = 0; i < 3; i++) {
    setTimeout(function() {
        console.log(i);
    }, 1000);
}
0
1
2

Fix using an IIFE (Immediately Invoked Function Expression):

for (var i = 0; i < 3; i++) {
    (function(i) {
        setTimeout(function() {
            console.log(i);
        }, 1000);
    })(i);
}
0
1
2

Closures in Event Handlers

Closures allow each event handler to remember its associated data.

function setupButtons() {
    for (let i = 0; i < 3; i++) {
        const btn = document.createElement('button');
        btn.textContent = 'Button ' + i;
        btn.onclick = function() {
            alert('Clicked button ' + i);
        };
        document.body.appendChild(btn);
    }
}

setupButtons();

Each button, thanks to the closure, correctly remembers its own i value when clicked.

Advanced Example: Partial Application

Closures can be used to create specialized versions of functions with some arguments preset.

function multiply(a) {
    return function(b) {
        return a * b;
    };
}

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

console.log(double(5)); // 10
console.log(triple(5)); // 15
10
15

Summary: Why Are Closures Important?

  • They enable data encapsulation and information hiding.
  • They help preserve state in asynchronous code and event handling.
  • They’re fundamental to functional programming patterns in JavaScript.

Frequently Asked Questions

Is a closure the same as a function?

Not quite. Every closure is a function, but not every function creates a closure. A closure is formed when an inner function “remembers” variables from its outer lexical scope.

Are closures bad for performance?

Closures use more memory since variables must be retained in the scope chain. But this is usually negligible unless closures are heavily created in performance-critical code.

Can closures be garbage collected?

Yes, as long as there are no more references to the closure or the variables it closes over, they will be garbage collected.

Next Steps

Mastering closures will significantly level up your JavaScript skills. You’ll see closures behind the scenes in libraries, callbacks, event handlers, and more. Practice writing your own closures and observe how scope is preserved!

Recognize the important boundary

Closures retain access to bindings, not automatically frozen snapshots. Avoid retaining large objects longer than necessary through unused callbacks.

Try a small variation

JavaScript · original source for practice

function rule(threshold) {
  return (mark) => mark >= threshold;
}
const passed = rule(50);
console.log(passed(72));

Your task: Replace rule(50) with rule(75). Predict the result before running the edited program.

The source is repeated here. If the edit targets the HTML rather than the script, use the markup repeated below; the worked answer also repeats the changed markup.

Worked answer and reasoning

The returned function now compares marks against its retained threshold of 75.

JavaScript · complete worked variation

function rule(threshold) {
  return (mark) => mark >= threshold;
}
const passed = rule(75);
console.log(passed(72));

Expected output

false
Run in JavaScript compiler →

Predict the original program

JavaScript · original program for this question

function rule(threshold) {
  return (mark) => mark >= threshold;
}
const passed = rule(50);
console.log(passed(72));
What does the original JavaScript program display, in order?
Choose one answer. You can try again.

Answer and explanation

true

A closure is a function together with access to its surrounding lexical bindings. A school rule factory can return a function that remembers a particular threshold after the outer call returns. Closures retain access to bindings, not automatically frozen snapshots. Avoid retaining large objects longer than necessary through unused callbacks.

Check the important distinction

Does a closure automatically freeze the value of every outer let?
Choose one answer. You can try again.

Answer and explanation

No. It keeps access to bindings, which can change.

A later call can observe an updated outer binding.

Keep the useful idea

A closure is a function together with access to its surrounding lexical bindings. A school rule factory can return a function that remembers a particular threshold after the outer call returns.

Check your variation against this explanation: The returned function now compares marks against its retained threshold of 75.

Use the JavaScript array reference library for individual array operations and boundary tests to check a rule independently.

Reaching the recap and completing the quizzes are separate milestones.

    Next lesson: Choose a Method's Receiver →