What are JavaScript closures?

What are JavaScript closures?

Definition and characteristics

closure in debugger

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.

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:

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.

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.

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”.

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”

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

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.

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.

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.

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.

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.

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.

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.