Day 15: Understanding Closures

Alpit KumarAlpit Kumar
4 min read

Screenshot:-

Closures are a fundamental concept in JavaScript that allows functions to access variables from an enclosing scope. This can be a bit tricky to grasp at first, but let's break it down with simple examples to make it easier to understand.

Activity 1: Understanding Closures

Task 1: A Function Returning Another Function

Here's an example of a function that returns another function. The inner function can access a variable from the outer function's scope:

function outerfun() {
  let num = 3;
  function innerfunc() {
    return num;
  }
  return innerfunc;
}

const print = outerfun();
console.log(print()); // Output: 3

In this example, innerfunc is a closure. It "closes over" the variable num from the outer function outerfun, allowing it to access num even after outerfun has finished executing.

Task 2: A Closure with a Private Counter

Closures can be used to create private variables. Here’s an example of a closure that maintains a private counter:

function createcounter() {
  let counter = 0;

  return {
    increment: function () {
      counter++;
    },
    getvalue: function () {
      return counter;
    },
  };
}

let counter = createcounter();
counter.increment();
console.log(counter.getvalue()); // Output: 1
counter.increment();
console.log(counter.getvalue()); // Output: 2

In this example, the counter variable is private to the createcounter function. The only way to access or modify counter is through the returned increment and getvalue methods.

Activity 2: Practical Closures

Task 3: Generating Unique IDs

Closures can be used to generate unique IDs by keeping track of the last generated ID:

function generateId() {
  let lastid = 0;

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

const generated = generateId();
console.log(generated()); // Output: 1
console.log(generated()); // Output: 2
console.log(generated()); // Output: 3

Here, the lastid variable is private to the generateId function, and each time the returned function is called, lastid is incremented and returned.

Task 4: Greeting a User by Name

Closures can capture and remember values. Here’s an example where we capture a username:

function takeusername(username) {
  let uname = username;
  return function () {
    return uname;
  };
}

const myname = takeusername("Alpit");
console.log(myname()); // Output: Alpit

In this example, uname is captured by the returned function, allowing it to remember and return the username.

Activity 3: Closures in Loops

Task 5: Ensuring Functions Log Correct Index in Loops

Closures can be used to ensure that functions created in a loop log the correct index:

function createfunctionarray() {
  let functionArray = [];

  for (let i = 0; i < 5; i++) {
    functionArray.push((function(index) {
      return function () {
        console.log(index);
      };
    })(i));
  }
  return functionArray;
}

const functions = createfunctionarray();
functions[0](); // Output: 0
functions[1](); // Output: 1
functions[2](); // Output: 2
functions[3](); // Output: 3
functions[4](); // Output: 4

In this example, we use an immediately invoked function expression (IIFE) to create a new scope for each function, capturing the current value of i.

Activity 4: Module Pattern

Task 6: Managing a Collection of Items

Closures can be used to create modules, which are self-contained pieces of code. Here’s an example of a simple item manager module:

const itemManager = (function () {
  let items = [];

  return {
    addItem: function (item) {
      items.push(item);
      console.log(`Added: ${item}`);
    },
    removeItem: function (item) {
      const index = items.indexOf(item);
      if (index > -1) {
        items.splice(index, 1);
        console.log(`Removed: ${item}`);
      }
    },
    listItems: function () {
      return items;
    },
  };
})();

itemManager.addItem("Apple");
itemManager.addItem("Banana");
itemManager.removeItem("Apple");
console.log(itemManager.listItems()); // Output: ["Banana"]

In this example, the items array is private to the item manager module. The only way to interact with items is through the provided methods.

Activity 5: Memoization

Task 7: Memoizing Function Results

Memoization is an optimization technique that stores the results of expensive function calls and returns the cached result when the same inputs occur again:

function memoize(fn) {
  const cache = {};
  return function (...args) {
    const key = JSON.stringify(args);
    if (cache[key]) {
      return cache[key];
    }
    const result = fn(...args);
    cache[key] = result;
    return result;
  };
}

function factorial(n) {
  if (n <= 1) return 1;
  return n * factorial(n - 1);
}

const memoizedFactorial = memoize(factorial);
console.log(memoizedFactorial(5)); // Output: 120
console.log(memoizedFactorial(5)); // Output: 120 (cached result)

In this example, memoize is a higher-order function that returns a memoized version of the factorial function.

By mastering closures, you can write more efficient and modular JavaScript code. Closures allow you to create private variables, encapsulate functionality, and optimize performance with techniques like memoization. Happy coding!

0
Subscribe to my newsletter

Read articles from Alpit Kumar directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Alpit Kumar
Alpit Kumar

I am a passionate web developer and open-source enthusiast on a captivating journey of coding wonders. With a year of experience in web development, my curiosity led me to the enchanting world of React, where I found a true calling. Embracing the magic of collaboration and knowledge-sharing, I ventured into the realm of open source, contributing to Digital Public Goods (DPGs) for the betterment of the digital universe. A firm believer in learning in public, I share my insights and discoveries through blogging, inspiring fellow coders to embark on their own magical coding odysseys. Join me on this thrilling adventure, where imagination and technology converge, and together, let's shape the future of the digital landscape! 🎩✨