Definition and characteristics

It is a known fact that when a function ends, all its local variables are picked up by the garbage collector and they cease to exist in memory. However, this is not the case for a function that contains a closure function.
Closures are functions that have access to variables that are in the domain of another function. This is most often achieved by embedding the function inside another function (thus defining the “scope chain”), after which the closure gains the ability to remember the reference to variables from the parent domain.
It should be noted that mutable external functions are not deleted upon execution of the function itself, but are kept in memory to be available to the closure function. After the execution of the closure function, the external function is also closed (hence the name “closure“). Until the closures are executed, JavaScript will also store the necessary variables from the domain of other functions, therefore they take up more memory than regular functions. Excessive use of closure can lead to increased memory consumption. The latest JavaScript engines manage to partially free the trapped memory, but it is still recommended to be careful when using closure.
As part of the debugger built into the browser, you can see the closure expression and which value of the variable is “remembered” (see picture).
An example of a standard closure f is
The function b() is nested inside the function a() and along the “scope chain” looks for a variable from the function a(), therefore it is a classic example of a closure function.
|
1 2 3 4 5 6 7 8 |
function a (){ var x = "This is closure"; function b (){ console.log (x); } b(); } a(); Returns: Ovo je closure |
Not every nested function is a closure
If the inner function does not use a variable from the outer functions in which it is located (along the “scope chain”), then it is not a closure. See the following example:
|
1 2 3 4 5 6 7 8 |
function a (){ var x = 5; function b (){ console.log ("This is a nested function, but not a closure!"); } b(); } a(); // Returns: This is a nested function, but not a closure! |
Closure remembers variables from outer function even though the outer function has been executed
It is known that after using the return command, the execution of the function and the existence of its variables in the temporary memory are interrupted. However, “Closure” remembers the variables from the outer function even if it returned a value with return.
|
1 2 3 4 5 6 7 8 9 |
function a () { var x = "This is a closure, even after the outer function has completed and returned a result"; function b () { console.log(x); } return b; } var c = a(); // We assign the return function to the variable "c" c(); // Returns: This is a closure, even after the outer function has completed and returned a result |
Closure “remembers” the reference pointed to by the variable
When it is said that the “closure function” has access to a variable, it means that it has access to a certain place in the memory pointed to by that variable, ie. to its reference at the time of calling “closure function“. If at that place in the memory, i.e. reference changes value, closure will always take the latest current value. The following example shows how the internal function “remembers” the reference and uses the current value in memory.
|
1 2 3 4 5 6 7 8 9 10 11 |
function povecajBrojac () { var brojac = 0; return function () { return brojac++; }; } var izbroj = povecajBrojac(); izbroj(); // Returns: 0 izbroj(); // Returns: 1 izbroj(); // Returns: 2 |
Redeclaring a variable
If, after defining clousure, we assign some other reference (place in memory that stores some value) to the variable that needs closure, clousure will use the reference that was in circulation at the time of defining clousure. In the following example, the function sayHello() at the moment of definition “remembers” a reference to the global variable “myName” (“Dragoljub”). So even though “myName” changes the reference which now contains the value “Marko”, the closure still uses the value “Dargoljub”.
|
1 2 3 4 5 6 7 8 9 10 |
var myName = 'Dragoljub'; var pozdrav = function(name){ return function(){ console.log('Hello ' + name + '!'); } } var pozdravSaImenom = pozdrav(myName); myName = 'Marko'; pozdravSaImenom();// Returns: Hello Dragoljub! |
However, this does not mean that the closure remembers the first defined value of a variable, but remembers the defined value of the variable at the time of definitionclosure. So in the following example the function returns “Marko”
|
1 2 3 4 5 6 7 8 9 10 11 |
var myName = 'Dragoljub'; var pozdrav = function(name){ return function(){ console.log('Hello ' + name + '!'); } } myName = 'Marko'; var pozdravSaImenom = pozdrav(myName); myName = 'Pera'; pozdravSaImenom();// Returns: Hello Marko! |
NOTE:
When the “new” keyword is used to create an object inside an outer function, IT DOES NOT CREATE A CLOSURE and the new function does not have a reference to the outer function’s local variable as a closure.
Application of the closure function
Troubleshooting “this” in a loopback callback function
The callback function in the loop gives unwanted results because it is not called immediately while the loop is spinning, but always “a little later” when the loop has already spun and reached the last value of the counter. Therefore, the callback function always uses the last value of the counter. This problem is solved by calling the callback function immediately (putting it in the IIFE) so that it “grabs” the value of the variable “i” at that moment, while the closure will do its part and remember what that value was. In this way, we create for each pass through the loop a new closure function, which “remembers” a different value of the variable “i”.
Example No. 1 – callback function setTimeout() method
|
1 2 3 4 5 |
for (var i = 0; i < 5; i++){ setTimeout(function(){ console.log(i); }, 1000); } // Returns: 5 5 5 5 5 |
After starting the loop, the initial value of the variable “i=0”, after which the function setTimeout() is called. The setTimeout() function will only call the callback function after 10s. While waiting for the callback function to be called, the loop continues to “spin” and now it is “i=1”, immediately after that the setTimeout() function is called, which will call the callback function again in 10s, and while waiting for its execution, the loop continues to spin and now it is “i=2”. The process is repeated until “i” gets a value of 5. This entire previously mentioned process is performed for a very short period of time (measured in milliseconds).
After the first 10 seconds, the loop has already “twisted” the variable “i” and the first callback function is invoked, which therefore takes the value of the variable “i”, which is 5. The next callback function for is activated for an additional 10 seconds, and uses the same variable, so the result is the same…
Problem solution:
In this example, we call the function at each round of the loop with the help of IIFE, thus providing it with unique values for each loop.
|
1 2 3 4 5 6 7 |
for (var i = 0; i < 5; i++){ (function(i){ setTimeout(function(){ console.log(i); }, 1000); })(i); } // Returns: 0 1 2 3 4 |
Example no. 2 – callback function addEventListener()
The following example shows a similar problem as with the loop and the setTimeout() function:
See the Pen VWPNPq by Web programming (@chos) on CodePen.
As in any standard loop, an eventListener is added to each element and the loop ends. The moment a button is clicked, the loop is already “twisted” and whichever button is selected, the alert will be the same.
Solution
One possible solution is to put the entire code in an IIFE that will be called at each round and the closure will remember the passed value:
See the Pen gRgyOy by Web programming (@chos) on CodePen.
Imitation of private data
JavaScript is a language that does not support private data in the same sense as some other programming languages, but using closure we canwe imitate this behavior. Everything is based on the closure property that it is the only one that has access to the variable in the outer function even after the function has finished. Since such a variable can only be accessed from a closure function, it can be considered private.
Constructor template for creating private data
The following code shows a standard constructor function with the “_name” object property.
|
1 2 3 4 5 6 7 |
function Person(name) { this.name = name; this.getName = function() { return this.name; }; } |
The variable “name” is not private because it can be accessed from the global domain. After creating a new object, it is possible to change the value of a variable by simply assigning a value to the object’s property.
|
1 2 3 |
var person = new Person("Pera"); person.name = "Dragoljub"; alert(person.getName()); // Returns the new value of the variable "Dragoljub" |
If we want to imitate the good practice of object programming from other languages and prevent access to this variable from the global domain, we will use closure and define a local variable instead of an object property.
|
1 2 3 4 5 6 7 |
function Person(name) { var _name = name; this.getName = function() { return _name; }; } |
Now the only way to “remember” the value of a variable when creating a new object is through the getName() closure. It is still possible to access the object’s property and change the value, but the closure returns the value of the variable when the object is constructed. This is explained in redeclaring a variable.
|
1 2 3 |
var person = new Person("Pera"); person._name = "Dragoljub"; alert(person.getName()); // Returns the stored value of the variable at the time of constructing the "Pen" object |
PRIVILEGED METHODS:
Method privileges are global methods that have access to private variables or functions.
In the following example, we create “privileged methods” that can modify private variables.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
function Person(name){ var _name = name; this.getName = function(){ return _name; }; this.setName = function (value) { _name = value; }; } var person1 = new Person("Pera"); var person2 = new Person("Steva"); console.log(person1.getName()); //"Pera" person1.setName("Dragoljub"); console.log(person1.getName()); //"Dragoljub" console.log(person2.getName()); //"Steva" |
The disadvantage of this procedure is that for implementation it is necessary to use a constructor template which instantiates these two methods (getName and setName) every time a new object is instantiated, the other methods can avoid this by using the prototype pattern.
NOTE:
The best implementation of private properties in JS is finally added in ES2022 with the hash # prefix.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
class Person { #_name constructor(name) { this.#_name = name; } getName (){ return this.#_name; }; setName (value) { this.#_name = value; }; } var person1 = new Person("Pera"); console.log("person1: ", person1.getName()); //"Pera" // Changing a private property with a privileged method: person1.setName("Dragoljub"); console.log("person1 (posle promene imena): ", person1.getName()); //"Dragoljub" var person2 = new Person("Mirka"); console.log("person1: ", person1.getName()); //"Dragoljub" console.log("person2: ", person2.getName()); //"Mirka" // Attempting to change a property without a privileged method would return an Error person1.#_name = "Steva" // ReturnsError |

