Lexical environment of functions in JavaScript

Let's consider the following code:

let num = 1; // set the value of the variable function func() { console.log(num); // print it to the console } func(); // call the function

As I mentioned earlier, the variable value does not have to be before the function definition, the main thing is that it should be before the function call:

function func() { console.log(num); } let num = 1; func();

In fact, this is not entirely true. Our function even before its call knows the value of the variable num:

let num = 1; function func() { console.log(num); // the function already knows that num = 1 }

Here's a more complicated example:

let num = 1; // the function at this point learns that num = 1 function func() { console.log(num); } num = 2; // the function at this point learns that num = 2

Add function calls:

let num = 1; // the function at this point learns that num = 1 func(); // shows 1 function func() { console.log(num); } func(); // shows 1 num = 2; // the function at this point learns that num = 2 func(); // shows 2

Once again: in fact, the function knows the values of external variables, even without being called.

Lexical environment

All external variables available to the function are called its Lexical Environment

In the following function example, two variables are available: num1 and num2, which are the lexical environment of our function:

let num1 = 1; let num2 = 2; function func() { // the function knows about the variables num1 and num2 }

The lexical environment itself is some kind of internal JavaScript object attached to our function. In this case, it can be represented as follows:

{num1: 1, num2: 2}

The value of any lexical environment variable is always equal to the current value of that variable:

let num1 = 1; // environment {num1: 1} let num2 = 2; // environment {num1: 1, num2: 2} // Let's change the variable num1: num1 = 123; // environment {num1: 123, num2: 2} function func() { }

When we try to refer to some variable inside a function, this variable is first looked up among the local variables of the function and, if such a variable is not there, then it is looked up in the lexical environment of the function.

Practical usage

Suppose we have a function that returns another function as its result:

function test() { return function() { } }

If the parent function has any variables, then those variables will be contained in the lexical environment of the returned function:

function test() { let num = 1; // the parent function variable return function() { // lexical environment = {num: 1} } }

Let's write an alert in the code of our returned function that displays the value of the variable num in the console:

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

Let's now call the parent function test and write the result of its work into the variable func:

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

The returned function will be written to the variable func. Let's call our function - as its result, it will display the contents of the variable num:

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

If you just try to display the variable num outside the function, it will be unavailable:

function test() { let num = 1; return function() { console.log(num); } } console.log(num); // the variable num is not available here

As you can see, the local variable num is bound to the lexical environment of our function, and now, by calling this function anywhere in the code, we can get the value of the variable num, even if at the place of the call this variable is not available by itself.

In fact, a similar result can be achieved by making the variable num global:

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

Here, however, there will be a significant difference: in the new version, the variable num can be changed outside of functions (since it is global), but not in the old one.

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

function test() { let num1 = 1; let num2 = 2; return function() { return num1 + num2; } } let func = test(); console.log(func());

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

function test() { let num1 = 1; let num2 = 2; return function() { return num1 + num2; } } console.log(test()());

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

function test() { let num1 = 1; return function() { return num1 + num2; } } let num2 = 2; let func = test(); console.log(func());

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

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