Skip to Content

Closures

2017-11-01

In this article, we'll cover such topics such scope and closure.We'll figure out what affects the scope of the variable, understand the mechanism for creating and working functions and variables, consider what a lexical environment is and how it works with variables that are not in the global scope but inside the function. In the end, in the chapter "Modules", we will discuss one example of the implementation of a closure in practice.

Global Object

Global names are variables and functions that are not inside a function. That is, in other words, if a variable or function is not inside the function construct, they are "global".

In JavaScript, all global variables and functions are properties of a special object, called a "global object".

In the browser, this object is explicitly available under the name ‘window’. The window object is simultaneously a global object and contains a number of properties and methods for working with the browser window.

By assigning or reading a global variable, we are actually working with window properties.

Initialization order

The script runs in two phases:

  • 1. In the first phase, initialization takes place, preparation for launch. During initialization, the script is scanned for declaring functions of the form function name (parameters) {...}, and then for declaring var variables. Each such declaration is added to the window. Ordinary functions of the form function name (parameters) {...} immediately after initialization can be called, and variables - undefined.
  • 2. In the second phase - actually, implementation.

Assignment (=) of variable values ​​occurs when the execution thread reaches the appropriate line of code, before that they are undefined.

The for, if ... constructs do not affect the visibility of variables. Visibility of variables is affected only by functions. Braces that are used in for, while, if, unlike function declarations, do not affect the visibility of variables.

In JavaScript, there is no difference between an ad outside the block:

var i;
{
i = 5;
}

... And inside it:

i = 5;
{
var i;
}

Also there is no difference between the announcement in a cycle and outside it:

for (var i = 0; i < 5; i++) {}

Identical in functionality code:

var i;
for (i = 0; i < 5; i++) {}

In both cases, the variable i will be created before the loop is executed, at the initialization stage of the code, i.e. Even before the cycle starts, and its value will be saved after the end of the cycle.

Lexical environment

All variables within a function are properties of a special internal LexicalEnvironment object, which is created when it starts. Also, when creating a function, it receives a special internal property [[Scope]] that references the lexical environment in which it was created.

At startup, the function creates a LexicalEnvironment object, writes arguments, functions, and variables there. The initialization process is performed in the same order as for the global object.

From a function, we can refer not only to a local variable, but also to an external variable. The interpreter, when accessing a variable, first tries to find it in the current LexicalEnvironment, and then, if it does not exist, it looks in the external LexicalEnvironment. This order of search is possible due to the fact that the reference to the external variable object is stored in the [[Scope]] property.

Note that if the variable is not found in the external LexicalEnvironment, then it is searched for in an even more external (via [[Scope]] external function). If the variable is not found anywhere, the result of the function will be an error.

The value of the variable from the outer region is always taken. It is worth noting that it may not be what it was when the function was created.

Module

Let's say we want to develop a script that does something useful on the page.

Hello.js file

// global variable of our script
var message = "Hello";

// function to display this variable
function showMessage () {
alert (message);
}

// output the message
showMessage ();

This script has its own internal variables and functions.

In this case, this is message and showMessage.

Supposing that we would like to distribute this script as a library, everyone who wants visitors to get "Hello" - can just connect this script. It is enough to download and connect, for example, as an external file hello.js - and it's ready.

If you connect a similar script to the page, then there may be a conflict with the variables that it uses.

That is, when you connect to such a page, it "breaks" it:

<script>
var message = "Please click the button";
</script>

<script> src = "hello.js"</script>

<button> Button </button>
<script>
// expect message from the variable above ...
alert (message);  // but in fact it will display "Hello"
</script>

The author of the page expects that the library "hello.js" will work without side effects. And it along with this is redefined the message in the "Hello."

If you remove the hello.js script, the page will display the correct message ("Please click the button").

Knowing the internal device hello.js, of course, we understand that the problem arose because the variable message from the hello.js script overwrote the one declared on the page.

That the problem was not necessary, that the script had its own scope, so that its variables not to get to the page.

To do this, we wrap all of its contents in a function, which we immediately start.

function () {

// global variable of our script
var message = "Hello";

// function to display this variable
function showMessage () {
alert (message);
}

// output the messageshowMessage ();

}) ();

This script will work correctly when connected to the same page.

"Hello" will be displayed, and then "Please click the button".

Today we looked at the scope that affects the scope of the variable at the closures being implemented in JavaScript and the advantages that closures give.

Author: Sergey Sheiko

Mifort, Mifort-blog, Mifort-articles, Web Development, JavaScript, Closures