🚀 LEVEL UP TO SENIOR:Unlock 500+ Advanced Practical Challenges & Exercises.
🎓 COURSERA PARTNER:Earn professional Google, Meta, and IBM certificates to supercharge your resume.
REFERENCEjavascript

javascript Documentation

LOADING ENGINE...

Closures

AI & DATA SCIENCE // closures

A closure is a function that remembers the variables from its outer scope even after the outer function has returned.

Syntax

function counter() {
  let count = 0;
  return () => count++; // closes over 'count'
}
const next = counter();
next(); // 1, next(); // 2

Deep Dive Course

A **closure** is formed when an inner function references variables from its outer (enclosing) function. The inner function 'closes over' those variables — they stay alive in memory as long as the inner function exists. Closures enable **private state**, **factory functions**, and the **module pattern**.

1Understanding Closures

A closure is formed when an inner function references variables from its outer (enclosing) function. The inner function 'closes over' those variables — they stay alive in memory as long as the inner function exists. Closures enable private state, factory functions, and the module pattern.

💡

Closures are the basis of most advanced JS patterns: currying, memoization, partial application, and the module pattern.

editor.html
// Counter with private state
function createCounter(initial = 0) {
  let count = initial; // private via closure

  return {
    increment: () => ++count,
    decrement: () => --count,
    value:     () => count,
    reset:     () => (count = initial)
  };
}

const c = createCounter(10);
console.log(c.increment()); // 11
console.log(c.increment()); // 12
console.log(c.value());     // 12
localhost:3000

2Practical Example

Here is a real-world application of Closures showing how it is used in production JavaScript code.

editor.html
// Classic closure-in-loop bug
const fns = [];
for (var i = 0; i < 3; i++) {
  fns.push(() => i); // all close over same 'i'
}
fns.forEach(f => console.log(f())); // 3 3 3 (bug!)

// Fix: use let
const fns2 = [];
for (let i = 0; i < 3; i++) {
  fns2.push(() => i); // each iteration has its own 'i'
}
fns2.forEach(f => console.log(f())); // 0 1 2 (correct!)
localhost:3000

3Best Practices

Follow these guidelines when working with Closures:

1. Use closures for private state encapsulation

2. Be aware closures prevent GC of outer scope variables

3. Watch for closure-in-loop bugs (use let or IIFE to fix)

⚠️

Tip: Closures are the basis of most advanced JS patterns: currying, memoization, partial application, and the module pattern.

editor.html
// Counter with private state
function createCounter(initial = 0) {
  let count = initial; // private via closure

  return {
    increment: () => ++count,
    decrement: () => --count,
    value:     () => count,
    reset:     () => (count = initial)
  };
}

const c = createCounter(10);
console.log(c.increment()); // 11
console.log(c.increment()); // 12
console.log(c.value());     // 12
localhost:3000

Examples

Example 01Basic Usage
// Counter with private state
function createCounter(initial = 0) {
  let count = initial; // private via closure

  return {
    increment: () => ++count,
    decrement: () => --count,
    value:     () => count,
    reset:     () => (count = initial)
  };
}

const c = createCounter(10);
console.log(c.increment()); // 11
console.log(c.increment()); // 12
console.log(c.value());     // 12
Example 02Advanced Example
// Classic closure-in-loop bug
const fns = [];
for (var i = 0; i < 3; i++) {
  fns.push(() => i); // all close over same 'i'
}
fns.forEach(f => console.log(f())); // 3 3 3 (bug!)

// Fix: use let
const fns2 = [];
for (let i = 0; i < 3; i++) {
  fns2.push(() => i); // each iteration has its own 'i'
}
fns2.forEach(f => console.log(f())); // 0 1 2 (correct!)

Best Practices

  • Use closures for private state encapsulation
  • Be aware closures prevent GC of outer scope variables
  • Watch for closure-in-loop bugs (use let or IIFE to fix)

Interview Question

What is the classic closure-in-loop bug and how do you fix it?

Hint: var vs let, shared reference vs per-iteration binding.

When using var in a for loop, all closures inside the loop share the SAME variable 'i'. By the time the closures run, 'i' equals the final value. Fix 1: use let — it creates a new binding per iteration. Fix 2: IIFE — wrap the callback in an immediately invoked function that captures the current value. Fix 3: closure factory function.

Exercises

MediumPractice using Closures in a real scenario.
View Solution
// Counter with private state
function createCounter(initial = 0) {
  let count = initial; // private via closure

  return {
    increment: () => ++count,
    decrement: () => --count,
    value:     () => count,
    reset:     () => (count = initial)
  };
}

const c = createCounter(10);
console.log(c.increment()); // 11
console.log(c.increment()); // 12
console.log(c.value());     // 12

Frequently Asked Questions

What is the classic closure-in-loop bug and how do you fix it?

When using var in a for loop, all closures inside the loop share the SAME variable 'i'. By the time the closures run, 'i' equals the final value. Fix 1: use let — it creates a new binding per iteration. Fix 2: IIFE — wrap the callback in an immediately invoked function that captures the current value. Fix 3: closure factory function.

Related Functions

Scope-ContextArrow-FunctionsthisCallback-Functions