Closures in JavaScript

Let's now study the concept of closure. In fact, you are already familiar with this concept, it remains only to learn the correct terminology.

So a closure is a function along with all the external variables that are available to it. Or, in other words, a closure is a function along with its lexical environment.

In JavaScript, most often, when they say "function closure", they do not mean this function itself, but its external variables. If some function gets a variable from its lexical environment, then we say "the variable is taken from the closure".

Let's remember the code we made in the previous lesson:

function test() { let num = 1; return function() { console.log(num); } } let func = test(); func(); // shows 1

In this case, we can say that the function func gets the value of the variable num from the closure. We can also say that the function func stores the value of the variable num in a closure.

Counter using closure

Let's rewrite our code so that the returned function increments the value of the variable num by one each time:

function test() { let num = 1; return function() { console.log(num); num++; // adds one } } let func = test();

It turns out that each call to the function func will output a new value to the console:

function test() { let num = 1; return function() { console.log(num); num++; } } let func = test(); func(); //shows 1 func(); //shows 2 func(); //shows 3 func(); //shows 4 func(); //shows 5

It turns out that we implemented the function call counter using a closure (more precisely, using the variable num from our function closure).

Note that each call to the function test will return a new function that will have its own closure. That is, different counters will work independently:

function test() { let num = 1; return function() { console.log(num); num++; }; }; let func1 = test(); // the first counter func1(); //shows 1 func1(); //shows 2 let func2 = test(); // the second counter func2(); //shows 1 func2(); //shows 2

It turns out that the same variable num will have different values for different functions!

That is, if we call the function test twice, then the functions derived from it will work independently and each of these functions will have its own independent variable num.

On your own, without looking into my code, implement a function call counter that works on closures.

Let the function store the number 10 in the closure. Make it so that each function call decrements this number by 1 and prints the decremented number to the console.

Modify the previous task so that the countdown goes up to 0, and then each subsequent function call prints a message to the console that the countdown has ended.

Nuance

Consider the following code:

function test() { let num = 1; return function() { console.log(num); num++; }; }; test()(); //shows 1 test()(); //shows 1

Why will the number 1 always be displayed? In order to understand this, let's rewrite our code differently:

function test() { let num = 1; return function() { console.log(num); num++; }; }; let func1 = test(); //!! the first function func1(); //shows 1 let func2 = test(); //!! the second function func2(); //shows 1

That is, each function test call like this: test()() creates its own function with its own closure and immediately calls this function.

Determine what will be output to the console without running the code:

function func() { let num = 0; return function() { console.log(num); num++; }; }; func()(); func()(); func()();

Determine what will be output to the console without running the code:

function func() { let num = 0; return function() { console.log(num); num++; }; }; let test = func; test()(); test()(); test()();

Nuance

Let's take the variable num out of functions, thereby making it global:

let num = 1; // the global variable function test() { return function() { console.log(num); num++; }; };

In this case, all returned functions will change this global variable and the counters will work already depending on each other:

let num = 1; function test() { return function() { console.log(num); num++; }; }; let func1 = test(); // the first counter func1(); //shows 1 func1(); //shows 2 let func2 = test(); // the second counter func2(); //shows 3 func2(); //shows 4

Why did our previous code make independent counters? Recall this code:

function test() { let num = 1; return function() { console.log(num); num++; }; };

The point is that the variable num is local inside the function test. Therefore, each call to test generates its own local variable.

Therefore, the each of returned functions will refer to its local function variable test. This is how independence is achieved.

If we make num a global variable, this will also be a closure. It's just that the lexical environments of returned functions refer to the same variable num - any changes to this variable will be visible in all functions.

Determine what will be output to the console without running the code:

let counter = 0; function test() { return function() { console.log(counter); counter++; }; }; let func = test; let func1 = func(); let func2 = func(); func1(); func2(); func1(); func2();

Determine what will be output to the console without running the code:

function test() { let counter = 0; return function() { return function() { console.log(counter); counter++; }; }; }; let func = test()(); let func1 = func; let func2 = func; func1(); func2(); func1(); func2();

Determine what will be output to the console without running the code:

function test() { let counter = 0; return function() { return function() { console.log(counter); counter++; }; }; }; let func = test(); let func1 = func(); let func2 = func(); func1(); func2(); func1(); func2();
enru