DEV Community

Cover image for Closures in JS ๐Ÿ”’
Bibi
Bibi

Posted on

Closures in JS ๐Ÿ”’

TL/DR:
Closures are a synthetic inner delimiter that inherits 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 a function that has access to variables in its outer (enclosing) lexical scope, 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

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

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

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

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

Top comments (4)

Collapse
 
jonrandy profile image
Jon Randy ๐ŸŽ–๏ธ • Edited

a closure is a function that has access to variables in its outer (enclosing) lexical scope, 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!

Maybe you should have quoted MDN verbatim, because your definition is incorrect. A closure is not a function, and ALL functions can access variables in their lexical scope.

Collapse
 
yourtechbud profile image
Noorain Panjwani

Using closures as function factories? Nice. An insightful and fun read as always. Thanks for sharing!

Collapse
 
muhammadanas8 profile image
MuhammadAnas8

Thanks for sharing

Collapse
 
officialphaqwasi profile image
Isaac Klutse

Nice article, fun to read