Today, let's talk about closures in Javascript. I know there are many blogs and articles talking about closures, but still, people seem to find this topic very difficult to understand. I will try to explain closures in my way, which I find easy to understand. Hope this will help you guys as well. Before diving into closures, lets first try to understand the below topics (understanding this will help us have a better understanding of closures)
- Scope of a function
- First Class functions
Scope of a function
In Javascript, whenever we create a function, it creates a scope. Any variables declared within the scope can be accessed throughout the function. So if we have a function, within a function, it will have access to all the variables of its parent function. Let's look into one example here.
function main(){
var a = 10;
var b = 25;
function test(){
console.log(a+b);
}
test();
}
main();
In the above example, we have a main function that has 2 variables, a and b. Inside the main function, we have another function test. Test doesn't have any variables of its own. It accesses the variable of its parent, in this case, it is the main function. When we run this code, we see the output to be 35, which is the sum of a and b (10+25).
35
Basically, javascript tries to see if the variables a and b are present inside the test function. If it's not present then it will try to check if these values are present in its parents. If that is also not presents it will try to check for the parent of the parent and so on. In our case, the values a and b were present in the parent, i.e the main function, so test did not throw any error.
Note: the variables can only the accessed from child to parent and not the other way around. If the variables a and b were present in the test function, the main function would not have access to these variables
Now that we have some idea of how the scope works in javascript, let's move on to first class functions.
First Class functions
Functions in javascript are treated like any other object. You can pass the function as an argument to another function, you can store it in a variable and also you can return functions from another function. Let's look at an example for each of these,
function assigned(){
console.log("this function is assigned to a variable");
}
var a = assigned;
a();
In this example, we are creating a function assigned to a variable and then calling it. This process of creating a named function and assigning it to a variable is called named function expression. Now let's see how we can pass a function as an argument to another function.
function one(x){
console.log(x());
}
function two(){
return "this is function two";
}
one(two);
In the above example, we are passing function two, which is returning a string to function one. If we run this we will see the following log.
this is function two
Usually, the function that is passing in as an argument is called as Callback function. We can also return a function from another function as shown in the example below.
function sample(){
function test (){
console.log("this is test function");
}
return test;
}
sample()();
Here we are creating a function test inside the function sample. We are not invoking test anywhere inside sample, but instead, we are returning it. We are invoking both the functions sample and function test by the two () brackets after sample as shown in the above code Sample()()
. When a function accepts other function as its argument or returns a function then it is called as higher order function. The output for the above code will be like this.
this is test function
Let's now use what we have learned till now and try to understand what closure is.
What are Closures?
We now know that any function inside another function will have access to all the variables of its parent function. We also know that we have the ability to return this function. So what will happen when we return a function that is accessing a variable of its parent function? Voilà, we have just understood what a closure is!
According to the definition from MDN "A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment)." Basically, any function which has access to the variables of its parent's scope, together with its parent scope forms a closure. Let's take an example.
function parent(){
var a = 10;
var b = 25;
function child (){
console.log(a+b)
}
return child;
}
var x = parent();
//300 lines of code;
x();
If we see the output of the above function, it will be the same as our first example.
35
In this example, we have returned the output of the parent function and assigned it to variable x. After doing some process in the 300 lines of code we decide to call the function stored in variable x to see if we still have access to the variables of the function parent. And we do!
But wait a minute, if we call the parent function and get back the child function, then if we try to access the variables of the parent function from the child function, should we not get undefined? Well, the answer is no. You see, this is the beauty of closures. Even when the parent function has finished its execution and is no longer available in the call stack, the variables used by the child functions will still be stored in the memory and will be available for reference for the child function. The javascript garbage collector does not clear the memory for any variables that are being used by a child function even after the execution of the parent function.
If that is the case, will it not consume more space than a normal function? Yes, it will. That's why we have to be careful not to bloat our code with closures, else it will affect the performance and might even cause memory leaks.
Conclusion
So closures are nothing but functions combined with variables of its lexical scope (parent scope). In theory, every function in javascript forms a closure as they all have access to variables in the global scope. Hope this explanation made your understanding of closures a little better. Closures are not a unique concept in javascript and are a pretty common concept in functional programming. Understanding closure will definitely help in getting a better understanding of other functional programming concepts.
Top comments (2)
Thanks for the article!
Just to adding a bit more to this, As a beginner if you are confused and want to see what references are being
closure'd
by a function, You can easily hitconsole.dir(functionReference)
in the console and expandScopes -> Closures
.Hope that's helpful. Happy Sunday!
Oh nice, I did'nt know about that. Thanks for sharing.