In depth understanding of JavaScript's advanced lexical scope and scope chain

  • 2020-03-30 00:50:52
  • OfStack

Main contents:
1. Analyze the meaning of lexical scope of JavaScript

2. Resolve the scope chain of variables

3. What happens when the variable name is promoted

Recently in the transmission of wisdom podcast to explain the course of JavaScript, many friends think JavaScript is so simple, but so do not know how to use, so I prepared some content to share with you.
The contents of this series covers the top part of the JavaScript, including the scope chain, closures, function call mode, prototype, and object-oriented something. Here does not include the basic syntax of JavaScript, if need to know basis of students can go to http://net.itcast.cn to download free video to learn. Ok, please donate said, direct access to our business.

One, about block-level scope
When it comes to JavaScript's variable scope, it's different from the usual c-like language.
For example, the following code in C# :


static void Main(string[] args)
{
 if(true)
 {
  int num = 10;
 }
 System.Console.WriteLine(num);
}

This code will not pass if compiled because "num" does not exist in the current context
Variables are scoped by curly braces and are called block-level scopes.

In block-level scope, all variables are inside the curly braces that are defined, from the beginning of the definition to the end of the curly braces
Scope can be used. Out of this scope is not accessible. That is to say, the code


if(true)
{
 int num = 10;
 System.Console.WriteLine(num);
}

This is accessible because the variables are defined and used in the same curly braces.

In JavaScript, however, there is no notion of block-level scope.

Scope in JavaScript
In JavaScript, the following code:


if(true) {
 var num = 10;
}
alert(num);

The result is a popover of 10. So how are variables scoped in JavaScript?

2.1 functions limit the scope of variables
In JavaScript, only functions can limit the scope of a variable.
That is, in JavaScript, variables defined inside functions can be accessed inside functions, but outside functions
Unable to access. See the following code:


var func = function() {
 var num = 10;
};
try {
 alert(num);
} catch ( e ) {
 alert( e );
}

When this code is run, an exception is thrown that the variable num is not defined
It can be used outside of the function, but it can be used freely inside the function, even before the assignment.


var func = function() {
 alert(num);
 var num = 10;
 alert(num);
};
try {
 func();
} catch ( e ) {
 alert( e );
}

When this code runs, it does not throw an error and pops up twice, undefined and 10(why, as explained below).

It can be seen from this that variables can only be accessed in a function, and so can functions in that function.


2.2 the child domain accesses the parent domain
As we said before, a function can scope a variable, so a function inside a function becomes a subdomain of that scope
The following code can access the variables in the parent domain:


var func = function() {
 var num = 10;
 var sub_func = function() {
  alert(num);
 };
 sub_func();
};
func();

The result of this code execution is 10. You can see the above mentioned variable access, but in the child domain access the parent domain
The code is also conditional, such as the following code:


var func = function() {
 var num = 10;
 var sub_func = function() {
  var num = 20;
  alert(num);
 };
 sub_func();
};
func();

This code has one more "var num = 20;" , this code in the child domain, then the child domain access to the parent domain
The result of this code print is 20. That is, the num accessed by the child domain is a variable in the child domain, not in the parent domain.

In JavaScript, variables are used, and the JavaScript interpreter does them first
Search the domain to see if there is a definition for that variable, and if so, use that variable; If not, look for the variable in the parent domain.
And so on, up to the top level scope, still not found on the exception "variable undefined ". See the following code:


(function() {
 var num = 10;
 (function() {
  var num = 20;
  (function(){
   alert(num);
  })()
 })();
})();

This code executes and prints out 20. If "var num = 20;" Take it out, and it will print 10. Again, if you take it out again
"Var num = 10", then an undefined error occurs.

Scope chain
With the JavaScript scope division, you can connect the JavaScript access scope into a chain tree structure.
Once the scope chain of JavaScript is clearly understood, the variables and closures of JavaScript are very clear.
The following drawing method, draw the scope chain.

3.1 drawing rules:
1) scope chain is an array of objects
2) all scripts are of level 0 chain, and each object occupies a position
3) generally see the function extends out of a chain, a level of expansion
4) access to the current function first, if there is no definition of the chain up to check
5) repeat until the chain reaches level 0

For example, 3.2
See the following code:


var num = 10;
var func1 = function() {
 var num = 20;
 var func2 = function() {
  var num = 30;
  alert(num);
 };
 func2();
};
var func2 = function() {
 var num = 20;
 var func3 = function() {
  alert(num);
 };
 func3();
};
func1();
func2();

Here's a look at the code:
- > First of all, the whole code is a global scope, which can be marked as a 0 level scope chain, so long as there is an array
Var link_0 = [num, func1, func2]; // this is described in pseudocode
- > Here func1 and func2 are functions, so two 1-level scope chains are derived, respectively
Var link_1 = {func1: [num, func2]}; // this is described in pseudocode
Var link_1 = {func2: [num, func3]}; // this is described in pseudocode
- > The first level 1 chain gives rise to the second level chain
Var link_2 = {func2: [num]}; // this is described in pseudocode
- > The second 1 - level chain has no defined variables, is an empty chain, is expressed as
Var link_2 = {func3: []};
- > By integrating the above code, the scope chain can be expressed as:


//This is described in pseudocode
var link = [ //The chain of level 0
 num,
 { func1 : [ //The first one chain
  num,
  { func2 : [ //Level 2 chain  
   num
  ] }
 ]},
 { func2 : [ //Second one chain
  num,
  { func3 : [] }
 ]}
];

- > Let's graph it as

< img border = 0 SRC = "/ / files.jb51.net/file_images/article/201312/20131210152307510.jpg" >

Figure: 01_01 scope chain. BMP

Note: the chain of the graph with js code, then highlighted when very clear.

With this scope chain diagram, it is very clear how to access variables:
When you need to use a variable, first look for the variable on the current chain. If you find it, use it directly. No
Look up; If not, then look up the chain of scope until level 0.


If you can clearly determine the level of the scope chain to which the variable belongs, then you are analyzing JavaScript
The code is much easier to code with advanced JavaScript features like closures (at least I am).

Three, variable name promotion and function name promotion

With access rules for scoped chains and variables, there is a very tricky problem
JavaScript code:


var num = 10;
var func = function() {
 alert(num);
 var num = 20;
 alert(num);
};
func();

What is the result of the execution? If you think about it, I won't give you the answer.

Let's examine this code first.
This code has a level 0 scope chain with member num and func. It has a level 1 function under func
A string of fields containing member num. Therefore, when the function func is called, the current scope is detected
The variable num is defined, so it is used, but num is not assigned because of the generation
The code runs from the top down, so the first time you print undefined, the second time you print 20.
Are you right?

The code is defined in the back like this, and the situation of using it in the front is also common in JavaScript
Problem. It is as if the variable was defined in the first place, and the result is the following code:


var num = 10;
var func = function() {
 var num; //It feels like it's already defined here, but there's no assignment
 alert(num);
 var num = 20;
 alert(num);
};
func();

Then this phenomenon is often called variable name promotion.


var func = function() {
 alert(" Call the outer function ");
};
var foo = function() {
 func();

 var func = function() {
  alert(" Call the inner function ");
 };

 func();
};

Okay, so how does this code work out? Or there should be something different, I don't leave the reader to think!
We'll do that in the next one.

Because of these differences, it is recommended that variables be written at the beginning of actual development,
That is, the variable is defined at the beginning of the function, similar to the C language. This is also in the js library
This is how it's done, like jQuery.

Four, summary

Okay, so this article is all about explaining what the lexical scope of JavaScript is, and explaining
How to analyze the scope chain, and the access to variables, leave one last exercise for the end!!

See the following code execution results:


if( ! "a" in window ) {
 var a = " Define variables ";
}
alert(a);


Related articles: