A closure is just any function that somehow remains available to invoke after its outer scopes have been invoked and returned, the closed function keeps having access to all variables of its outer scopes in-where it has been defined.
In other words, A closure is a way to keep having access to local scope variables after their functions have been returned.
The definition might look confusing but with a simple example, I am going to make that clear to you.
let’s write a simple JavaScript program that displays the full name for a person.
First, let’s define a global variable for the last name:
var lastName = "Smith";
Next, we add a function to display the full name, and initialize the middle name variable inside,
var lastName = "Smith"; // Function to display the name and the middlename var displayFullName = function() { var middleName = randomName(); return; }
Notice that randomName here is just a fake function that returns a random name.
If you are willing to follow along and run the code of this tutorial, I recommend using chance library to generate random names.
Inside that function, I am gonna define another function named firstNameAndDisplay, the role of that function is to define a new variable for the last name and finally print the full name.
var lastName = "Smith"; // Function to display the name and the middlename var displayFullName = function() { var middleName = randomName(); // firstNameAndDisplay function function firstNameAndDisplay = function() { var firstName = randomName(); return console.log(firstName+middleName+lastName); } return firstNameAndDisplay; }
Finally, we call the function: displayFullName
displayFullName(); // output: JohnDoeSmith
Each time we call the displayFullName function we get a new random middleName and a new random firstName, then the full name will be displayed.
Let’s say that we want to generate random first names but we want to fix the middle name at its first generated value, How could we achieve that with the code above?
To do that, we need to preserve the function firstNameAndDisplay somehow for future invoking after displayFullName function have been returned, so after that, we can call it globally to generate new first names while preserving the old middle name value.
The best way to do that is to push that function to a global array variable. in that way, we say that we have enclosed that function to that array and that’s where the term closure comes from, the function after that will be available in the global scope.
var lastName = "Smith"; // array to hold firstNameAndDisplay function objects var closures = []; // Function to display the name and the middlename var displayFullName = function() { var middleName = randomName(); // Instead of defining that function we push to an array closures.push(function() { var firstName = randomName(); return console.log(firstName+middleName+lastName); }); return; } // initialization displayFullName(); /* * Now we have one function object in closures array. * we can call that function Now */ closures[0](); // output: JohnChristianHelge
By running the enclosed function multiple times, we get random first names, but the middle name stays the same: Christian
closures[0](); // output: JohnChristianZandra closures[0](); // output: JohnChristianAlannah closures[0](); // output: JohnChristianBarry
Now if we want to get a new generated middle name at any point of our program we simply invoke displayFullName function again, here’s the full example:
var lastName = "Smith"; // array to hold firstNameAndDisplay function objects var closures = []; // Function to display the name and the middlename var displayFullName = function() { var middleName = randomName(); // Instead of defining that function we push to an array closures.push(function() { var firstName = randomName(); return console.log(firstName+middleName+lastName); }); return; } // initialization displayFullName(); /* * with the first middle name */ closures[0](); // output: JohnChristianZandra closures[0](); // output: JohnChristianAlannah closures[0](); // output: JohnChristianBarry closures[0](); // output: JohnChristianHelge /* * Generate a new middle name */ displayFullName(); /* now we should call the second function in the closures array */ closures[1](); // output: JohnGritKevia closures[1](); // output: JohnGritWilliam
So by running the function displayFullName a second time, a new function object gets pushed to the closures array, and now we have 2 enclosed functions.
I hope that makes sense, if you have any questions, leave them in the comments below, if you liked the tutorial don’t forget to share it with your friends, I truly appreciate it 🙂