DevPrep
  • Interview Prep
  • Projects
  • Resources
  • Pricing
  • About Us
Submit Question
DevPrep
  • Pricing
  • About Us
Submit Question
  1. Home
  2. Articles
  3. Frontend Engineering
  4. JavaScript Closures in Depth: Memory, Performance, and Patterns
XLinkedInReddit
MediumFrontend Engineering

JavaScript Closures in Depth: Memory, Performance, and Patterns

D
DevPrep Team
February 10, 2026·2 min read·0
Table of Contents
  • What is a Closure?
  • Memory Implications
  • The Classic Loop Problem
  • Closure Patterns
  • Memoization
  • Module Pattern

Closures are the most important concept in JavaScript. They power React hooks, module patterns, and event handlers. Let me show you the deep mechanics.

What is a Closure?

A closure is a function that remembers the variables from its lexical scope, even after that scope has finished executing.

function createCounter() {
  let count = 0; // This variable is "closed over"
  return {
    increment: () => ++count,
    getCount: () => count
  };
}

const counter = createCounter();
counter.increment(); // 1
counter.increment(); // 2
// count is private — no way to access it directly

Memory Implications

Closures keep their outer scope alive. This can cause memory leaks if you're not careful.

// Memory leak example
function attachHandler() {
  const hugeData = new Array(1000000).fill("x"); // 1M strings
  const element = document.getElementById("button");
  
  element.addEventListener("click", () => {
    console.log(hugeData.length); // hugeData stays in memory!
  });
}

// Fix: only close over what you need
function attachHandler() {
  const hugeData = new Array(1000000).fill("x");
  const length = hugeData.length; // Extract needed value
  
  element.addEventListener("click", () => {
    console.log(length); // Only length is retained
  });
}

The Classic Loop Problem

// Bug: all callbacks print 5
for (var i = 0; i < 5; i++) {
  setTimeout(() => console.log(i), 100); // 5, 5, 5, 5, 5
}

// Fix 1: let (block scoping)
for (let i = 0; i < 5; i++) {
  setTimeout(() => console.log(i), 100); // 0, 1, 2, 3, 4
}

// Fix 2: IIFE (closure creates new scope)
for (var i = 0; i < 5; i++) {
  ((j) => setTimeout(() => console.log(j), 100))(i);
}

Closure Patterns

Memoization

function memoize(fn) {
  const cache = new Map();
  return function (...args) {
    const key = JSON.stringify(args);
    if (cache.has(key)) return cache.get(key);
    const result = fn.apply(this, args);
    cache.set(key, result);
    return result;
  };
}

const expensiveCalc = memoize((n) => {
  console.log("Computing...");
  return n * n;
});
expensiveCalc(5); // Computing... 25
expensiveCalc(5); // 25 (cached)

Module Pattern

const API = (() => {
  let baseURL = "";
  const headers = {};
  
  return {
    configure(url, token) {
      baseURL = url;
      headers.Authorization = `Bearer ${token}`;
    },
    get: (path) => fetch(baseURL + path, { headers }),
    post: (path, body) => fetch(baseURL + path, { method: "POST", headers, body: JSON.stringify(body) })
  };
})();

Related Articles

MediumFrontend Engineering

System Design #12: Design a Multi-Step Form Wizard

7 min read
MediumFrontend Engineering

Mastering Senior-Level JavaScript Interview Concepts

2 min read
MediumFrontend Engineering

System Design #9: Design a Collaborative Text Editor

9 min read

Comments (0)

Sign in to leave a comment.

No comments yet. Be the first to comment.

Table of Contents

  • What is a Closure?
  • Memory Implications
  • The Classic Loop Problem
  • Closure Patterns
  • Memoization
  • Module Pattern

Series

View all Frontend Engineering articles →

Practice

  • JavaScript
  • DSA
  • Machine Coding
  • System Design

Resources

  • Learning Tracks
  • Articles
  • Roadmaps
  • Compare Concepts
  • Glossary
  • Developer Tools
  • All Questions

Company

  • About
  • Pricing

Legal

  • Privacy Policy
  • Terms of Service
DevPrep

© 2026 DevPrep. All rights reserved.