Closures in JS 🔒
Tags: javascript, webdev, career, tutorial
Published: 2024-06-26 03:38:46


_**TL/DR:**
Closures are a synthetic inner delimiter that has access to its parent's scope, even after the parent function has finished executing._

Not clear? I didn't get it either. Read along partner!

---

## 🔒 Closures 🔒

Ah, closures. Sounds pretty straight forward... whatever's inside the curly braces right?! Well, yes and no. This topic is quite simple but there's a lot to explore in it, you'll wonder whether you accidentally stumbled into a parallel universe after reading, I guarantee. But fear not, my fellow wizards, for today we shall unravel the enigma that is closures! 

First, let's start with the textbook definition because I love a good MDN reference: 

> a closure is the combination of a function bundled together with references to its surrounding state (the lexical environment), even after the outer function has returned. Kinda like having the key to a treasure chest of variables, even when you've left the pirate ship!

Okay that wasn't MDN verbatim, but you get the idea. So, how does this sorcery work?? Well, when you create a function within another, the inner one has access to the variables and parameters of the outer function. This is because the inner function forms a closure, maintaining access to the environment in which it was created. It's like the inner function remembers its surroundings!

Here's a classic example to illustrate closures:

![1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bnnt15izhwdv2tqauf1i.png)

In this example, `outerFunction` takes a parameter `x` and has a local variable `y`. It defines an `innerFunction` that accesses both `x` and `y`, and then returns the `innerFunction`. When we assign the result of calling `outerFunction(5)` to the variable closure, we are essentially capturing the `innerFunction` along with its environment (where `x` is 5 and `y` is 10). Even though `outerFunction` has finished executing, the closure still remembers the values of `x` and `y`, allowing us to invoke it later and get the expected output of 15.

This was just a simple example, but closures actually have various practical applications, such as data privacy, factories, and memoization. They allow you to create functions with private state and encapsulate behaviour, leading to more modular and reusable code. Let's do a deeper dive into these specific applications:


**1. Private Variables and Encapsulation** 🔒

Closures can be used to create private variables and achieve encapsulation. Consider the following example:

![2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7qq12moir5p0n9brmhit.jpg)

In this example, the `createCounter` function returns an object with an `increment` method. The count variable is defined within the `createCounter` function and is not accessible from the outside. The `increment` method, being a closure, has access to the `count` variable and can modify it. Each time `counter.increment()` is called, the `count` is incremented, but it remains private and cannot be accessed directly from the outside.

---

**2. Function Factories** 🏭 
Closures can be used to create function factories, which are functions that generate other functions with customized behaviour. Here's an example:

![3](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8b433rryq6nxioupj6ki.jpg)

In this case, the `multiplyBy` function takes a `factor` parameter and returns a new function that multiplies a given `number` by the `factor`. We create two separate functions, `double` and `triple`, by calling `multiplyBy` with different factors. Each returned function forms a closure, capturing its own `factor` value, allowing us to multiply numbers by the respective factors.

---

**3. Memoization** ⏰ 
Closures can be used to implement memoization, which is a technique to cache the results of expensive function calls and return the cached result when the same inputs occur again. Here's an example of memoizing a factorial function:

![4](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6uptx379uq4dt3tmbgb4.jpg)

In this example, the `memoizedFactorial` function returns a closure that serves as the actual `factorial` function. The closure maintains a `cache` object to store previously computed results. Whenever the `factorial` function is called with a number `n`, it first checks if the result is already in the cache. If it is, it returns the cached result. Otherwise, it calculates the factorial recursively and stores the result in the cache before returning it. Subsequent calls with the same `n` will retrieve the result from the cache, avoiding redundant calculations.

---

These examples are obviously simple but the applications of closures in JavaScript can be much more complex. They can provide a powerful mechanism for data privacy, code organization, and optimization, when done right!

However, closures can also lead to some gotchas if not used carefully. One common pitfall is creating closures in loops, where the closure captures the last value of the loop variable. But that's a story for another day! 

---

## Alright, I think that's it for me ┗(･ω･;)┛

Here are some key points to take home:
* A closure is a function that remembers the environment in which it was created. It has access to variables and parameters of the outer function.
* It allows a function to access variables from its outer (enclosing) scope, even after the outer function has finished executing.
* Closures can access and manipulate variables from the outer scope, even after the outer function has returned.


Hope you learned something with me today! (´◡`)
Bibi