≡ Menu

📝 JavaScript Closures Tutorial

1. 🚪 What is a Closure?

 

A closure is a fundamental and often-misunderstood concept in JavaScript. In simple terms, a closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment).

Simply put: A function remembers and can access variables from the scope it was declared in, even when that function is executed outside that scope.

  • Lexical Environment (Scope): This is the local memory where variables are defined, plus the memory of its parent scope. “Lexical” means it’s determined at the time of writing/compiling the code, not at runtime.


2. 🔎 How Do Closures Work? (The Mechanics)

 

Closures are created every time a function is created. To understand them, consider a function that returns another function.

Example 1: The Basic Mechanism

 

function outerFunction(outerVariable) {
  // outerVariable is part of the outerFunction's lexical environment
  return function innerFunction(innerVariable) {
    // innerFunction uses variables from its own scope (innerVariable)
    // AND from its parent's scope (outerVariable)
    console.log('Outer Variable:', outerVariable);
    console.log('Inner Variable:', innerVariable);
  };
}

// 1. When `newFunction` is created, it maintains a reference to 
//    the lexical environment of `outerFunction` where 'hello' was defined.
const newFunction = outerFunction('hello'); 
outerFunction = null; // Even if we set the reference to null, it still works!

// 2. When `newFunction` is executed here, *outside* `outerFunction`, 
//    it still "closes over" and accesses the 'hello' variable.
newFunction('world'); 

// Output:
// Outer Variable: hello
// Inner Variable: world

Key Takeaway

 

When the outerFunction finishes executing, its scope (the area where outerVariable lives) should normally be destroyed.

However, because innerFunction (the closure) still holds a reference to that scope, the JavaScript engine keeps that specific state alive in memory.


3. 🛠️ Practical Use Cases for Closures

 

Closures are not just a theoretical concept—they are used everywhere in modern JavaScript to solve common problems.

A. Data Privacy / Encapsulation (Module Pattern)

 

The most common use is to hide variables from the global scope, protecting them from accidental modification, similar to how private variables work in other object-oriented languages.

function createCounter() {
  let count = 0; // This variable is private!

  return {
    increment: function() {
      count++;
      return count;
    },
    decrement: function() {
      count--;
      return count;
    },
    getCount: function() {
      return count;
    }
  };
}

const counter = createCounter();

console.log(counter.increment()); // 1
console.log(counter.increment()); // 2

// You cannot directly access `count` from here:
// console.log(counter.count); // undefined or error

console.log(counter.getCount()); // 2

In this example, the count variable is only accessible through the three returned public methods (increment, decrement, getCount), which are the closures.

B. Function Currying / Partial Application

 

Closures allow you to create specialized functions from a more general function by pre-setting some arguments.

function multiply(a) {
  return function(b) {
    return a * b; // Closes over 'a'
  };
}

const double = multiply(2); // 'a' is set to 2
const triple = multiply(3); // 'a' is set to 3

console.log(double(5));  // Output: 10 (2 * 5)
console.log(triple(5)); // Output: 15 (3 * 5)

C. Asynchronous Operations (e.g., Event Handlers)

 

Closures are essential for callbacks, especially in loops, to ensure that the function accesses the correct value of the loop variable at the time the function is executed, not when it was declared.


4. ⚠️ The Classic Closure Pitfall: Loops

 

Understanding this pitfall is crucial for mastering closures.

The Problem (Using var)

 

When you use var inside a loop to declare the variable that the closure references, all closures created inside the loop will reference the same single variable instance.

for (var i = 1; i <= 3; i++) {
  setTimeout(function() {
    console.log(i); // This closure closes over the SAME 'i'
  }, i * 100);
}

// Wait 100ms, 200ms, 300ms...
// Output (The value of 'i' *after* the loop is done):
// 4
// 4
// 4

The Solution (Using let or an IIFE)

Since ES6, the easiest fix is using let, as let is block-scoped and creates a new instance of the variable for each loop iteration.

for (let j = 1; j <= 3; j++) {
  setTimeout(function() {
    console.log(j); // This closure closes over the new 'j' for this iteration
  }, j * 100);
}

// Output (The correct value for each iteration):
// 1
// 2
// 3

📚 Conclusion

 

Closures are a powerful feature that makes advanced patterns like function factories and data encapsulation possible in JavaScript. By understanding that a function carries a backpack of its surrounding variables with it, you unlock a deeper understanding of how JavaScript manages scope and memory.

Useful links below:

Let me & my team build you a money making website/blog for your business https://bit.ly/tnrwebsite_service

Get Bluehost hosting for as little as $1.99/month (save 75%)…https://bit.ly/3C1fZd2

Best email marketing automation solution on the market! http://www.aweber.com/?373860

Build high converting sales funnels with a few simple clicks of your mouse! https://bit.ly/484YV29

Join my Patreon for one-on-one coaching and help with your coding…https://www.patreon.com/c/TyronneRatcliff

Buy me a coffee ☕️https://buymeacoffee.com/tyronneratcliff

{ 0 comments }

The To-Do List is the “Hello World” of web applications—and for good reason!

It teaches you the essential flow of modern web development: handling user input, manipulating the Document Object Model (DOM), and styling user feedback.

In this tutorial, we will build a functional, persistent To-Do list using only HTML, CSS, and vanilla JavaScript.

🛠️ Prerequisites

 

  • A basic understanding of HTML tags and CSS properties.

  • A text editor (like VS Code).

  • A web browser.

Let’s start by creating three files: index.html, style.css, and script.js.

Step 1: HTML Structure (The Skeleton)

 

The HTML sets up the basic layout: a header, an input area for new tasks, and an unordered list (<ul>) to hold the tasks. We use IDs to easily target these elements later with JavaScript.

HTML:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JS To-Do List</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="container">
        <h1>My Task List</h1>
        <div class="input-area">
            <input type="text" id="task-input" placeholder="Enter a new task...">
            <button id="add-button">Add Task</button>
        </div>
        
        <ul id="todo-list">
            </ul>
    </div>

    <script src="script.js"></script>
</body>
</html>

Step 2: CSS Styling (The Look)

 

We will use simple CSS to make the application clean, centered, and visually indicate completed tasks.

CSS:

/* style.css */
body {
    font-family: Arial, sans-serif;
    background-color: #f4f4f9;
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
    margin: 0;
}

.container {
    background-color: #fff;
    padding: 30px;
    border-radius: 8px;
    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
    width: 100%;
    max-width: 450px;
}

/* --- Input Area Styling --- */
.input-area {
    display: flex;
    margin-bottom: 20px;
}

#task-input {
    flex-grow: 1;
    padding: 10px;
    border: 1px solid #ccc;
    border-radius: 4px 0 0 4px; /* Rounded left corners */
}

#add-button {
    background-color: #007bff;
    color: white;
    border: none;
    padding: 10px 15px;
    border-radius: 0 4px 4px 0; /* Rounded right corners */
    cursor: pointer;
    transition: background-color 0.2s;
}

#add-button:hover {
    background-color: #0056b3;
}

/* --- List Styling --- */
#todo-list {
    list-style: none;
    padding: 0;
}

#todo-list li {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 10px;
    margin-bottom: 8px;
    background-color: #eee;
    border-radius: 4px;
    cursor: pointer;
    transition: background-color 0.2s;
}

/* Style for completed tasks */
.completed {
    text-decoration: line-through;
    color: #888;
    background-color: #d9d9d9 !important;
}

/* --- Delete Button Styling --- */
.delete-btn {
    color: #ff4d4d;
    font-weight: bold;
    margin-left: 15px;
    cursor: pointer;
}

Step 3: JavaScript Logic (The Brain)

 

Now for the core logic. We need functions to add a task, toggle its completion status, and delete it.

3.1 Setup & Element Selection

 

We start by selecting the HTML elements we need to interact with.

JavaScript:

// script.js
const taskInput = document.getElementById('task-input');
const addButton = document.getElementById('add-button');
const todoList = document.getElementById('todo-list');

// Attach the event listener to the Add button
addButton.addEventListener('click', addTask);
// Also allow adding tasks by pressing 'Enter'
taskInput.addEventListener('keypress', function(e) {
    if (e.key === 'Enter') {
        addTask();
    }
});

3.2 The addTask() Function

 

This function handles creating the new list item element and inserting it into the DOM.

JavaScript:

// script.js (continued)

function addTask() {
    const taskText = taskInput.value.trim();

    // 1. Basic validation: Don't add empty tasks
    if (taskText === "") {
        alert("Please enter a task!");
        return;
    }

    // 2. Create the list item (li)
    const listItem = document.createElement('li');
    listItem.textContent = taskText;

    // 3. Create the delete button (span)
    const deleteBtn = document.createElement('span');
    deleteBtn.textContent = 'X';
    deleteBtn.classList.add('delete-btn');

    // 4. Attach event listeners to the new item

    // Click on the task itself to mark complete/incomplete
    listItem.addEventListener('click', function() {
        listItem.classList.toggle('completed');
    });

    // Click on the 'X' to delete the task
    deleteBtn.addEventListener('click', function(e) {
        // Stop the 'completed' toggle from firing when clicking delete
        e.stopPropagation(); 
        listItem.remove();
    });

    // 5. Assemble and append
    listItem.appendChild(deleteBtn);
    todoList.appendChild(listItem);

    // 6. Clear the input field for the next task
    taskInput.value = '';
}

Bonus Step: Data Persistence (Never Lose Your List!)

 

To prevent the list from disappearing when the user refreshes the page, we use the browser’s localStorage.

3.3 Adding Storage Logic

 

Wrap the previous logic in functions that also interact with localStorage.

  1. Modify addTask to also save to storage.

  2. Create saveTasks to update storage every time.

  3. Create loadTasks to rebuild the list when the page loads.

(Since this involves slightly more complex state management, I’ll stop here to keep the post brief, but this is a fantastic follow-up tutorial!)


Wrap-up

Congratulations! You now have a fully functional To-Do List application. This project demonstrated the core skills of front-end development:

  • HTML: Creating the basic page structure.

  • CSS: Styling for usability and aesthetics.

  • JavaScript: Dynamically creating elements (createElement), handling user events (addEventListener), and modifying the DOM (appendChild, toggle, remove).

Useful links below:

Let me & my team build you a money making website/blog for your business https://bit.ly/tnrwebsite_service

Get Bluehost hosting for as little as $1.99/month (save 75%)…https://bit.ly/3C1fZd2

Best email marketing automation solution on the market! http://www.aweber.com/?373860

Build high converting sales funnels with a few simple clicks of your mouse! https://bit.ly/484YV29

Join my Patreon for one-on-one coaching and help with your coding…https://www.patreon.com/c/TyronneRatcliff

Buy me a coffee ☕️https://buymeacoffee.com/tyronneratcliff

{ 0 comments }