A JavaScript closure is the combination of a function (which may be nested together) and the lexical environment within which the particular function is declared. Lexical environment is the internal JavaScript engine construct that holds identifier-variable mapping. Also, a JavaScript variable may be local or global. While the global variables are declared in global scope which can be called anywhere in the project context, the execution or access to local variables can be only inside the defined scope. However, these global variables can be converted into local using JavaScript closure.
Let us take an example of lexical scoping:
function start() {
var topic = 'closure'; // topic is a local variable created by init
function display () { // display() is the inner function, a closure
alert(topic); // use variable declared in the parent function
}
display();
}
start();
The outer function start() creates a local variable called topic and a function called *display(). *Likewise, the display() function is an inner function that is defined inside start() and is only available within the body of the start() function. As a result, the display() function has no local variables of its own. However, since inner functions have access to the variables of outer functions, display() can access the variable name declared in the parent function, start(). If display() were to have its own name local variable, it would use ‘this’ instead.
Furthermore, this showcases an idea of lexical scoping, which describes how a parser resolves variable names in nested functions. The word “lexical” refers to the fact that lexical scoping uses the location where a variable is declared within the source code to determine where that variable is available. Therefore, nested functions can call variables declared in their outer scope.
The JavaScript code below can properly represent Javascript Closure.
function closureStart() {
var topic = 'closure';
function display() {
alert(topic);
}
return display;
}
var myClosure = closureStart();
myClosure();
Above all, the execution of this code has the same effect as the previous example of the start() function above; the only difference is that outer function returns the display() function before it’s execution.
As a result, it may look unintuitive and confusing, but this code still works. In certain programming languages, the local variables within a function exist only for the period of execution of that function. Once closureStart() execution is complete, you might expect that the topic variable would no longer be accessible. Since the code still works as expected, this is not the case in JavaScript.
Besides, the reason is that functions in JavaScript form closures. This environment consists of any local variables that were in-scope at the time during the creation of a closure. In this case, myClosure is a reference to the instance of the function display() created when closureStart() is run. The instance of display() maintains a reference to its lexical environment, within which the variable name exists. Hence, during the invoking of myClosure, the variable name remains available for use. Therefore, passing “Closure” to alert.
JavaScript Closure is efficient due to the fact that they let you associate some data with a function that operates on that data. This is directly related to object-oriented programming, where objects allow us to associate some raw data (the object’s properties) with one or more methods in JavaScript project. You can make use of JavaScript closure anywhere that you might usually use an object with only a single method.
These situations are commonly utilized in web-based programming. The code we facilitate in front-end JavaScript are mainly event-based. We define some behavior, then assign it to an event that the user triggers. The code is generally attached as a callback: a single function which execution takes place in response to a particular event.
For instance, if we wish to add some buttons to a page that adjust the font size. One way of doing this is to specify the font-size of the body element in pixels, then set the size of the other elements on the page (such as body, divs) using the relative em unit:
div {
font-family: Arial, sans-serif, Consolas;
font-size: 11px;
}
.div1 {
font-size: 2em;
}
p {
font-size: 1em;
}
Therefore, the buttons can change the font-size property of the body element, and other elements will adjust based on the relative units.
Here’s the JavaScript Code:
function changeSize(input) {
return function() {
document.body.style.fontSize = size + 'px';
};
}
var button1 = changeSize(8);
var button2 = changeSize (12);
var button3 = changeSize (18);
document.getElementById('div1').onclick = button1;
document.getElementById('div2’).onclick = button2;
document.getElementById(‘div3’).onclick = button3;
<div href="#" id=" div1">JavaScript Closure</a>
<div href="#" id=" div2">Useful</a>
<div href="#" id=" div3">Always</a>
As a result, button1, button2, and button3 are now functions which when executes resizes the body text to 8, 12 and 18 pixels respectively.
Some programming languages such as Java, C#, Python, etc. have the capability of declaring methods private. Hence, other methods in the same class can only call these methods. JavaScript doesn’t have the capability to do this, but it is possible to emulate private methods using JavaScript closure. Private methods are very useful for restricting access to the code. They also provide an efficient way of organizing your global namespace, keeping non-essential methods from cluttering up the public interface to your code.
The following example describes the use of JavaScript closure to define public functions that can access private methods and variables:
var calculate = (function() {
var number = 0;
function add(value) {
number = number + value;
}
return {
increase: function() {
add(2);
},
decrease: function() {
add(-2);
},
display: function() {
return number;
}
};
})();
console.log(calculate.display()); // logs 0
calculate.increase();
calculate.increase();
calculate.increase();
console.log(calculate.display()); // logs 6
calculate.decrease();
console.log(calculate.display()); // logs 4
Here, we define a single lexical environment that is shared by three methods: calculate.increase(), calculate.decrease(), and calculate.display().
The shared lexical environment is defined inside some unknown function, whose execution takes place as soon as it is defined. The lexical environment contains two private instances: a variable called number and a method called add(). Both of these private items are not accessible directly from outside the function. They must be accessed by calling the three public functions that are returned from the anonymous wrapper. Those three public methods are JavaScript closure that shares the same environment. With the feature of JavaScript’s lexical scoping, there is access to the number variable and add function.
There are three scopes for every closure. They are as follows:
Therefore, all three scopes are accessible for closure. But often, we make a common mistake when having nested inner functions. Let us consider the following example:
// global scope
var num = 100;
function add(x){
return function(y){
return function(z){
// outer functions scope
return function(a){
// local scope
return x + y + z + a + num;
}
}
}
}
console.log(sum(10)(20)(30)(40)); // log 200
// We can also write without anonymous functions:
// In global scope
var num = 100;
function add(x){
return function add2(y){
return function add3(z){
// outer functions scope
return function add4(a){
// local scope
return x + y + z + a + num;
}
}
}
}
var p = add(10);
var q = add2(20);
var r = add3(30);
var s = add4(40);
console.log(s) //log 200
Here, nesting of a series of methods takes place which has access to the outer functions’ scope. But which incorrectly estimate only for their immediate outer function scope. Hence, all JavaScript closure have access to all outer function scopes within which they there declaring takes place.
Before the introduction of the let keyword in ES2015. JavaScript closure suffered from a problem when closures are defined inside the loop. Let us consider an example:
var array = [];
for (var k = 0; k < 3; k++) {
array[k] = function() {
console.log("k value is" + k);
};
}
for (var k = 0; k < 3; k++) {
array[k]();
}
The output of the above code will be:
k value is 0
k value is 1
k value is 2
The result here is incorrect. Hence, The actual correct output is :
k value is 2
k value is 2
k value is 2
This is due to the working mechanism of JavaScript closures and representation of k internally. Accordingly, the illustration of a solution for JavaScript Closure in a loop is as follows:
for (let k = 0; k < 3; k++) {
array[i] = function() {
console.log("k value is " + 3);
}
}
Therefore, let scopes the variable to for loop and produces a new value each iteration. Hence, the code assigns k with different values on our closures producing an accurate result.
JavaScript Closure is a powerful and widely used feature of Javascript. Understanding it is key to better coding. Creation of closure takes place when you declare a function. JavaScript Closure combines the function and its environment to its parent, thus enabling access to functions and variables of the parent. The closure persists after the execution of the parent completes.
#javascript #web-development