Prerequisites
Before looking at closures, please make sure you fully understand what scope is. I’m working on an article about scope and I will share the link here as soon as it’s done.

What exactly are closures?
MDN says:

“A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment).”

Sounds scary at first.
To put it simply, a closure is nothing more than a scope that gets returned by a function together with its return value.

For example, let’s consider a function that returns an object that has two methods.

//Code Snippet 1
function makeADog(name){
const dogName = name;
return {
bark: function(){
console.log(dogName + " says woof!")
},
sleep: function(){
console.log(dogName + " says ZzZz....")
}
}
}

Let’s focus on the return value of makeADog for a second.

//Code Snippet 2
{
bark: function(){
console.log(dogName + " says woof!")
},
sleep: function(){
console.log(dogName + " says ZzZz....")
}
}

If you were presented with this piece of code, with no context at all, you would most likely wonder “Where’s the missing code? Where is dogName being declared? This isn’t going to work.” And you would be right to do so. After all, if you copy-paste and run the code in Code Snippet 2 you would get “ReferenceError: Can’t find variable: dogName”. But here’s the catch, this does not happen with our example because of the closure that gets generated when we call makeADog().

When we call makeADog(), it not only returns the object but it also implicitly returns the variable dogName that we declare.
It’s as if makeADog() made the object and thought “You might need dogName for this to work so here it is I’m passing it along as well”.
The outer function is “bundling” all the variables together with the return value before actually returning it.

The same exact thing happens when we return a function instead of an object.
Let’s look at a classic example:

//Code Snippet 3
function makeAdder(x) {
return function(y) {
return x + y;
};
}

And just to be consistent, let’s look at the return value only, like we did with the previous example:

//Code Snippet 4
function(y){
return x + y;
};

Again, when we look at the return value only, an unnamed function this time, it makes no sense at first glance. Why would a function only take “y” as a parameter if it has to return “y + x”? What is “x” and where is it being declared?

In this case, our outer function makeAdder takes the value “x” which gets bundled and returned implicitly together with the inner function.

The returned function has no name, and its only use is to add another number “y” to “x”.
Imagine it this (weird) way: makeAdder takes a value “x” and returns some kind of a living being (an adder, if you will) whose only purpose in life is adding another number “y” to “x”. I know, weird, but it makes sense to me somehow.

But wait, how do we actually use the returned function/object? We can call makeAdder and makeADog because they have a name but what about their return values? Those have no name so how are we supposed to access or invoke them? Great question!

Well, how do we access/save/keep the return value from any other kind of function, closure or non-closure? We store it in a variable!

//Code Snippet 5
const dogTest = makeADog("Scooby");
const adderTest = makeAdder(3);

If you console.log(dogtest, adderTest) you’ll see that their values are exactly the same as Code Snippets 2 and 4. We are returning an object and a function respectively and storing them in a variable.
**When you console.log a function without putting the parentheses after the function name, you actually log the code content of that function. If you add the parentheses instead you log the result of invoking that function.

Now that we have them stored in a variable, we can invoke them like so:

//Code Snippet 6
dogTest.bark() // Scooby says woof!
dogTest.sleep() // Scooby says ZzZz....
adderTest(7) // 10
adderTest(5) // 8

Note that adderTest() is now a function with a name, it has the name of the variable we stored it in. It’s the same as declaring it like this:

//Code Snippet 7
function adderTest(num){
return num + 3;
}

What are some practical uses?
Closures don’t have one specific use per se. They’re an abstract concept and as such we can use them when we best see fit.
They’re often used to create private variables that are only accessible to the inner function that gets returned together with the closure.
For example, let’s say you have to keep count of how many times the user pressed a key or clicked an object.

You could just write the code as follows:

//Code Snippet 8
let counter = 0;
function increaseCounter(){
return ++counter;
}
increaseCounter(); //Counter becomes 1

But this way, counter would be a global variable just out there and accessible to any method.
You might need to declare another “counter” variable down the line and find that the name is already taken. It’s generally not a good idea to have variables just floating around where they’re not needed.
It’s also worth noting that other scripts on the page can also access a global variable making this a poor choice from a security perspective.

Well then, why not declare the variable inside the function? Let’s see:

//Code Snippet 9
function increaseCounter(){
let counter = 0;
return ++counter;
}

Indeed this would hide the variable from anything outside increaseCounter but as you can hopefully tell, this function would be unusable as counter would be set to 0 every time we call it.
Here’s a simple way to solve this by making use of closures.

//Code Snippet 10
function makeIncreaseCounter(){
let counter = 0;
return function(){
return ++counter;
}
}
const increaseCounter = makeIncreaseCounter();
increaseCounter();

Closure magic! We build a function which we can call from anywhere, that has access to a “hidden” variable counter which doesn’t get reset every time we call it. How amazing is that?

We could have achieved the same result with an object that has a counter property and an increaseCounter method but Closures vs Objects is a different topic for a different day :)

Ciao ciao!