JavaScript Closures – The only concept to define Private Data in JavaScript
Free Web development courses with real-time projects Start Now!!
JavaScript provides us with a lot of freedom in terms of functions. We can dynamically create a function, copy it to another variable, call it from a different place in your program or pass it as a parameter to another function. We can access variables defined inside (local variables) as well as outside the function. But what happens when the value of the variable changes during execution? Or if multiple functions access the same variable and one of them changes the value? Our code will be in shambles, and this will lead to unwanted results. How to solve this? The answer to that question is JavaScript Closures. You don’t have to know JavaScript closures as a beginner. But, if you wish to get an in-depth understanding of how JavaScript works, this topic is crucial for you. Understanding the working of any programming language is better than learning the syntax. It gives you better tools when you encounter an error or when you want to perform debugging.
Before moving further, please complete the JavaScript Regular Expression Tutorial
The Lexical Environment in JavaScript
Every time you create a scope in your program with the help of the curly braces { }, you create an internal (hidden) associated object called a lexical environment. It can be defined with a running function, code block, or an entire script. It is a logistical concept, and there is no way to access it from your JavaScript code. There are two components of a lexical environment:
- Environment Record – This is the object that stores all the local variables as its property.
- A reference to the outer lexical environment (binds the outer code).
You need to remember that when the code wants to access a variable, it starts from the inner lexical environment (inner scope of the local variables), then moves outwards to the outer lexical environment. It finishes its search after it goes through the global lexical environment.
Problems with Function Scope
Many a time, it happens that we modify the value of a variable in our program during execution. Also, some functions use the same variables. So the question that arises here is this: When we change the variable value, does the value in the function changes too? Let’s find out with the help of some simple codes that present us with different situations.
Situation 1: When we use a global variable in the function.
Code:
<html> <body> <script> let count = 0; // global variable declared function sayHello(){ count++; //increments the value of the global variable } sayHello(); document.write("Hello DataFlair.</br> Counter: " + count + "</br>"); count = 7; // global variable redeclared sayHello(); // uses redeclared variable name sayHello(); document.write("Counter: " + count + "</br>"); </script> </body> </html>
Screenshot:
Output:
Oops! Something went wrong, didn’t it? We wanted to count how many times we called the function sayHello() using a global variable that stores its value. Instead, the last line in our output suggests that we accidentally incremented the redeclared variable of the global variable. Let’s try again. But this time, we’ll use a local variable to do that for me.
Situation 2: When we use a local variable in the function.
Code:
<html> <body> <script> document.write("Using local variables:</br>") function Counter(){ let count = 0; // local variable declared count++; // increments the value of the variable return function(){ document.write("Counter: " + count + "</br>"); } } var myFunction = Counter(); myFunction(); myFunction(); myFunction(); </script> </body> </html>
Screenshot:
Output:
Okay, that really wasn’t the output I wanted. What happened? Well, we used the local variable in our function, which resets every time a function returns. Thus after each function call, the count returns to zero.
The problem with the above functions was that we misinterpreted the function scope. What we need to understand is that during a function invocation, the script creates a new scope for that call. Thus, we need to remember that the function scope is for a function call, rather than the function itself.
Well, these two approaches failed, big way. But wait, don’t be disappointed, JavaScript has something for you to solve this problem just right: Closures.
Wait a minute! Have you learned about JavaScript Variable Declaration
What are JavaScript Closures?
In the above problem, we need to create ‘private’ variables for a function in a way that they don’t reset after the function returns. We can achieve the desired output with the help of closures. A closure is a combination of a function and the lexical environment where we declared the variable. It can access the parent scope even after the parent function closes. This environment contains any local variables that were in-scope at the time of closure creation. You might be wondering how that is possible, right?
Closures make use of self-invoking functions in JavaScript. Since these functions run only once, they set the values of the variables and then returns a function expression. The important fact is that they are “nested functions”, thus they can access the outer variables (variables in the parent scope). Let’s understand this approach with the help of an example.
Situation 3: When we use a closure.
Code:
<html> <body> <script> document.write("DataFlair: Using Closures</br>") function Counter(){ let count = 0; // local variable declared return function(){ count++; //increments the value of the variable document.write("Counter: " + count + "</br>"); } } var myFunction = Counter(); myFunction(); myFunction(); myFunction(); </script> </body> </html>
Screenshot:
Output:
In this example, the count is protected by the scope of the anonymous, and we can only alter it while using the Counter() function. The program below makes the working of a closure a little more clear.
Code:
<html> <body> <script> function addNumbers(num1){ //closure return function(num2){ return num1 + num2; }; } // calling the outer function for num1 var add20 = addNumbers(20); var add30 = addNumbers(30); // calling the inner function for num2 document.write("Sum1:</br>20 + 30 = " + add20(30) + "</br>"); document.write("Sum2:</br>30 + 70 = " + add30(70) + "</br>"); </script> </body> </html>
Screenshot:
Output:
Notice that the parent function for add20 and add30 returned before we accessed the inner functions. It is because both of them are closures, saving the parent properties. Thus, we got the exact output we wanted. Try doing that with the help of a regular function and compare the two outputs.
Determining whether a given Function is Closure or not
Alright, we learned how to define a closure in our program. Now, we will find out whether a given function is a closure or not? Is there any way you can differentiate them from a normal function? Yes, there is. You can do that by noticing the inner function. Can you access the inner function directly? Do you have the means to call the nested function without its parent function? If the answer is no, then my friend, you’ve got a JavaScript closure.
It is because, in a closure, you can access an inner function only with the help of its parent function. It prevents an unauthorized user from accessing all the properties of the closure. In other programming languages like Java, we use access modifiers to define private properties in a class. Since we don’t have such a keyword available in JavaScript, we use closures.
Remember, you will often see that the inner function is anonymous. The reason is that it works as a wrapper around the code you want to protect from outer access.
Time to revise the different types of JavaScript Functions
Why are JavaScript Closures so important?
Closures are very useful when you want to define private properties in JavaScript. Some programmers prefix private properties with an underscore (_), indicating that you should not modify that property. But this does nothing to implement information hiding, rather gives the warning to be careful while using these values. On the other hand, closures are like a welcome mat between the outer scope and the rest of the program. They are magical since they allow us to achieve private data in JavaScript.
The problem in JavaScript Closure Loop
Before the introduction of ECMAScript 2015, there was a common problem while using closures with loops. The problem is clear from the code below.
Code:
<html> <body> <script type="text/javascript"> var variables = []; //creating an empty array for (var iterator = 0; iterator < 3; iterator++) { //adding values to the array (closure) variables[iterator] = function() { console.log("My value: " + iterator); }; } //iterating through each value in the array for (var iterator2 = 0; iterator2 < 3; iterator2++) { variables[iterator2](); } </script> </body> </html>
Screenshot:
We expected the value as follows:
My value: 0
My value: 1
My value: 2
The output we get is, as shown below:
Unexpected, wasn’t it? The problem lies with the variable declaration. There are two ways you can solve this problem. First, you can change the name of the iteration variable of the second loop so that it doesn’t always run with the value 3 (set by the previous for loop). Another approach you can use in modern browsers is the use of ‘let’ keyword for variable declaration. It prevents the continuous changing of the variable’s value and gets the desired output.
Output:
Do you know about JavaScript Loop Control Statements
Much better now, and just what we wanted the output to be. Experiment with this code and other codes where you use closures inside a function. You need to practice numerous problems to master the concept. If you get stuck, come back to the JavaScript closures tutorial and try to find out the problem when you get stuck.
Summary
In this tutorial, we learned a lot about JavaScript closures. We discussed the various problems with a normal function and how JavaScript closures help in that case. We also reviewed why we need closures in our JavaScript program.
Thinking, what to learn next? Here is the JavaScript Garbage Collection Tutorial for you.
Feedbacks and suggestions for us? Mention them in the comment section of JavaScript Closures Tutorial. We will be glad to hear from you. Keep visiting DataFlair for regular updates.
Happy Learning!
Your opinion matters
Please write your valuable feedback about DataFlair on Google