Technical Details

Mastering Closures in JavaScript: A Beginner's Guide

← Technical Details
2023-01-09 ~ 2026-06-21 · 3 min read
Mastering Closures in JavaScript: A Beginner's Guide
Discuss this article with your AI
Copy page

💡 Quick Summary (TL;DR):

  • What is a Closure?: A closure is the combination of a function bundled together with references to its surrounding state (the lexical environment).
  • Core Feature: Inner functions retain access to scope variables of their outer function even after the outer function has finished executing.
  • Common Use Cases: Creating private variables/encapsulation, function factories, and maintaining state in callbacks.
  • Memory Caution: Since closures keep variables in memory, they prevent garbage collection for those references, which can lead to memory overhead if overused.

Closures are a fundamental concept in JavaScript, and they can be a little tricky to understand at first. However, once you grasp how they work, they become an incredibly powerful tool in your JavaScript development toolkit.

Simply put, a closure is a function that remembers the environment in which it was created, even when it is executed outside of that environment.


Scope Access Levels inside a Closure

Scope LevelAccessible?Description
Local ScopeYesVariables declared directly inside the inner function itself.
Outer Function ScopeYesVariables and parameters of the parent outer function (lexical scope).
Global ScopeYesGlobally defined variables accessible anywhere in the script.

Understanding Lexical Scope: A Basic Example

To understand this concept better, let's take a look at a basic example:

function outerFunction(param) {
  let outerVariable = 'I am the outer variable';

  function innerFunction() {
    console.log(outerVariable + ', and the param is ' + param);
  }

  return innerFunction;
}

let returnedFunction = outerFunction('Hello, World!');
returnedFunction();

In this code, we have an outer function called outerFunction and an inner function called innerFunction.

The outerFunction takes a parameter called param and declares a local variable called outerVariable. The innerFunction has no parameters of its own, but it references both outerVariable and param belonging to the outerFunction.

When we call outerFunction('Hello, World!'), it returns the innerFunction itself. Crucially, when we execute returnedFunction() later, it still has full access to outerVariable and param even though outerFunction has already finished executing. This is a closure in action: innerFunction has closed over the lexical environment of outerFunction.

Output in the console:

I am the outer variable, and the param is Hello, World!

Practical Example: Data Encapsulation (Private Variables)

One of the most valuable use cases for closures is creating private variables. JavaScript classes now have native private fields (#privateField), but closures remain the classic, highly-flexible way to achieve encapsulation.

Consider this counter factory:

function createCounter() {
  let count = 0; // Private state variable

  return {
    increment() {
      count++;
      return count;
    },
    decrement() {
      count--;
      return count;
    },
    getValue() {
      return count;
    }
  };
}

const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.count);       // undefined (cannot be accessed or mutated directly!)
console.log(counter.getValue());   // 2

In this example, the count variable cannot be accessed from outside the createCounter function. The returned methods (increment, decrement, getValue) form a closure over the environment containing count, allowing safe access and modification while keeping the actual data hidden.


A Word on Memory Management

While closures are incredibly useful, they come with a performance trade-off: memory retention.

Normally, when a function finishes executing, JavaScript's Garbage Collector frees up the memory associated with its local variables. However, because a closure holds a reference to the outer function's scope, those variables remain in memory as long as the inner function is alive.

If you create many closures or hold references to large objects inside them without releasing the inner functions when they are no longer needed, it can lead to memory overhead.

Bu Yazıda Yapılan Değişiklikler
  • 21.06.2026: Veri gizleme (data encapsulation) amacıyla createCounter kullanılarak fonksiyon kapatması (closure) örneklendirildi. Kapatmaların Garbage Collector davranışları ve hafıza yönetimi (memory leaks) üzerindeki etkileri teknik olarak açıklandı. Scope seviyelerini listeleyen tablo ile özet paneli eklendi.