DEV Community

Cover image for [JavaScript] Understand closures in 111 seconds
Đặng Đình Sáng
Đặng Đình Sáng

Posted on

[JavaScript] Understand closures in 111 seconds

Although closures are a fundamental idea in JavaScript, newcomers may find them vague and challenging to grasp. Specifically, the ECMA standard's definition can be challenging to comprehend without any real-world experience. As a result, rather than going into great length to explain the notion of closures in this post, we will make it easy for you to comprehend by using actual code.

1. Closure

function A(name){
    function B(){
       console.log(name);
    }
    return B;
}
var C = A("Closure");
C();//Closure
Enter fullscreen mode Exit fullscreen mode

This is the simplest closure.

Now that we know the fundamentals, let us briefly examine how this differs from a typical function. The following is how the aforementioned code appears when translated into natural language:

  1. Define a normal function A, with argument name
  2. Define a regular function B in A, and in B, refer to the external variable name
  3. Return B in A
  4. Execute A and assign the result to variable C
  5. Run C

One statement can encapsulate these five operations:

Function B inside function A and variable name are referenced by variable C outside function A.

With a little modification, this statement defines a closure as follows:

A closure is created every time a function is created—at the time when the function is created. Every function has an associated closure. Nesting functions are not required.

Therefore, performing the above five operations defines a closure.

Uses of Closures

Before we understand the uses of closures, let's understand JavaScript's GC (Garbage Collection) mechanism.

In JavaScript, when an object is no longer referenced, it will be reclaimed by the GC, otherwise, it will continue to be kept in memory.

In the above example, B depends on A because B is defined within A, and A is indirectly referenced by C because the external variable C references B.

That is, A will not be collected by the GC and will continue to be kept in memory. To prove this reasoning, let's slightly improve the above example.

function A(){
    var count = 0;
    function B(){
       count ++;
       console.log(count);
    }
    return B;
}
var C = A();
C();// 1
C();// 2
C();// 3
Enter fullscreen mode Exit fullscreen mode
  1. If we call var C = A();, A is executed, creating a count variable and an internal function B. Since A returns B, the C variable actually has a reference to B. The function B can then access the count variable in A.
  2. Function B can access the count variable in A because B is a closure. This is because B is a closure, and closures preserve the context in which they are created (e.g., local variables).
  3. When C() is called, it actually calls function B. Each time C() is called, B increments the value of count and displays that value on the console.
  4. A's execution context ends when B is created, but A's local variables are not reclaimed as long as B references its local variables (such as count).
  5. Only when B is no longer referenced will the count variable and other local variables in A be recovered. In this example, since C still refers to B, the value of count is not recovered, nor is the execution context of A.

Why is count not reset?

Closure mechanism:

  • The closure keeps the state of count and keeps it accessible to the internal function B. Even if the execution context of A terminates, the state of count remains in memory because B continues to refer to this state.
  • On each call to B: Each call to C() is actually a call to B(), which uses the count stored in the closure and does not reinitialize it.

Thus, if you define some variables in a module and want to keep these variables in memory but not “pollute” the global variables, you can define this module using closures.

Top comments (1)

Collapse
 
jonrandy profile image
Jon Randy 🎖️ • Edited

When an inner function is referenced by a variable outside the outer function, a closure is formed.

Unfortunately, this isn't correct. A closure is created every time a function is created - at the time when the function is created. Every function has an associated closure. Nesting functions is not required.