Javascript is a functional programming language. Javascript can have nested functions, which means, a function can contain
another function, and so on. The child function can have access to the sccope of its outer environment, which means the child
function can access the variables of the parent function. Now, the parent function variables are within the
reach of the child function due to lexical scope. This concept is called closure.
Let's understand a bit more about- what is closure? Let's
go ahead and understand the advance concept of closure, real world usage of closure, design patterns in closure, memory leaks in closure,
how garrbage collector work with best example.
Acording to Mozilla Developer guide - A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.
Deeper into the closure- Advance closure concept
function parent(){ var a = 10; function child(){ return a; } return child; } var childRef = parent();
In above example: Even though the execution of the parent function is over, childRef
has access to var a=10;
.
Javascript engine generally destroys the variables of a function once the function execution is over. It is done by the garbage collector.
But in the above example, due to closure, it does not destroy the variable from the memory, because it is within the reach of child function.
Closure, memory leak and Garbage collector- When the parent function have lots of members they will be under lexical scope of child function. So, even though the parent function execution is over they will ramain in the memory Unnecessarily. There is a datailed article about how garbage collector works and its relation with closuser. To understand more about garbage collector and memory leak, follow this article-Can closure lead to memory leak?
Closure and lexical scope
Child function not only remembers its outer lexical scope but also remembers the arguments passed to its parent.
var city = function(city){ return function(user){ return user + ' is from ' + city } } var user1 = city('NY'); var user2 = city('LA'); user1('John'); // John is from NY user2('Alex'); // Alex is from LA
If we try to execute the above example by putting a debugger, We can see that city
value is persisting as a closure. Check the
red highlighted area in the image below.
When we execute line no 10, it execute child function by passig an argument name
, but at the same time it remembers in which
city
the user belongs to. This is possible becasue of the closure.
Now you understand closure and how it is formed. Try to relate to a real-world example and usage.
From the above example you can see that we have hold the execution of greatGrandChild
by putting a debugger, We can see a
red color rectangular box on the right side which holds the values of its outer lexical scope within a closure.
Closure with callback function
Now, take a look at the below example
function parent(child){ var age = 20; var childFn = child; return childFn(); } function child(){ console.log('age', age); } parent(child);
We are passing callback function to the parent function. Parent function is storing the callback function in a variable childFn
.
According to closuer concepts- A inner function withing a function forms a closure. In the above example, we have childFn
which is
inside parent
function. But this will not form closure and upon executing will result to error. It is becasue childFn
is reference to a outside function, it is not the member of parent function. When childFn
will execute, it will be executed outside
the scope of parent
funcion. You can keep debugger at line var age = 20;
and traverse the code line by line, you can
see the control flow goes to function child()
which is outsie of parent function.
Closure exercise for you
Now, you are know what closure is, here is an exercise for you. Try this once this artice is over. write a "Hello World" example using closure. Here are 3 conditions to print the "Hello World".
- Your function should be an example of closure
- It should print "Hello World" 5 time
- It should print with the innterval of 3 seconds
Program is very simple, yet complex. I repeat again- Print "Hello World" 5 times with the interval of 3 seconds using closure.
From example one- We understand that the private members of a function are not accessible from outside of its scope. So, one thing is clear; that a function hides its members from its outer environment. We can use this capability to hide the member from its outer environment; yet provide an interface to access them using child functions. We can use this capability to encapsulate all the features and all the private members within a module and expose what is only needed. We call it encapsulation and data hiding.
Closure and Design pattern
Yes, closure is one of the most important concepts of Javascript. We can leverage it by using it for different scenarios.
Using the closures, we can create a modular design pattern, function currying pattern, and higher-order functions.
function interestCalculator(){ var SIMPLE_INTEREST_RATE = 6; var COMPOUND_INTEREST_RATE = 6; var whatIsInterestRate = function() { return { simpleInterest: SIMPLE_INTEREST_RATE, compoundInterest: COMPOUND_INTEREST_RATE, } } var simpleInterest = function simpleInterest(principleAmount, time){ var interest = (principleAmount * SIMPLE_INTEREST_RATE * time) / 100; return { interest, sum: principleAmount + interest, } } var compoundInterest = function compoundInterest(principleAmount, time){ var total = principleAmount * Math.pow((1+ (COMPOUND_INTEREST_RATE/100)), time); return { interest: total-principleAmount, sum: total, } } return {whatIsInterestRate, simpleInterest, compoundInterest}; } var interest = interestCalculator();
In the above example, SIMPLE_INTEREST_RATE and COMPOUND_INTEREST_RATE are private
members of interestCalculator function. They can not be accessed
or modified outside. The child functions of interestCalculator form closure. When we execute
interestCalculator function, it returns the reference to its inner functions.
Above example is a small demonstration of the modular design pattern. Here we are encapsulating all the related feature withing
the function and also hiding interest rates from ouside environment.
See the above image, you might have seen or created soemthing similar in your project, a step UI. We generally breakdown the feature in steps and then allow users to follow the steps. If i create a simple javascript function to mock the step feature, it will look like this.
function stepCalculator(){ var current = 1; function next(){ if(current < 3){ current = current + 1; return current; } } function back(){ if(current > 1){ current = current - 1; return current; } } return {next, back}; } var step1; = stepCalculator(); step1.next(); // it will return next step; step1.back(); // it will return previous step; var step2 = stepCalculator(); // this will create a fresh new step
In the above example when we invoke stepCalculator
function, it returns its inner functions enclosed within an object.
Because inner function forms closurer they have access to current
valiable. We can invoke stepCalculator
as many times we want.
Everytime it will return with a fresh new current
variable initialised with zero.
0 Comments