Main content:
1. Analyze the meaning of JavaScript lexical scope
2. Parse the scope chain of variables
3. What happens when variable names are promoted?
Recently, I was explaining JavaScript courses on Chuanzhi Podcast. Many friends felt that JavaScript was so simple, but they didn’t know how to use it, so I prepared some content to share with you.
This series mainly explains the advanced parts of JavaScript, including scope chains, closures, function calling patterns, prototypes and object-oriented things. The basic syntax of JavaScript is not included here. If you need to know the basics, students can go to http: Go to //net.itcast.cn to download free videos for learning. Okay, without further ado, let’s go directly to our topic.
1. About block-level scope
Speaking of JavaScript's variable scope, it is different from the C-like language we usually use.
For example, the following code in C#:
Copy the code code as follows:
static void Main(string[] args)
{
if(true)
{
int num = 10;
}
System.Console.WriteLine(num);
}
If this code is compiled, it will not pass because "the name num does not exist in the current context". Because here
The scope of variables is limited by curly braces and is called block-level scope.
In block-level scope, all variables are within the curly braces of definition, from the beginning of the definition to the end of the curly braces.
It can be used within the scope. It cannot be accessed outside this scope. In other words, the code
Copy the code code as follows:
if(true)
{
int num = 10;
System.Console.WriteLine(num);
}
It is accessible here because the variable is defined and used within the same curly braces.
But it's different in JavaScript. There is no concept of block-level scope in JavaScript.
2. Scope in JavaScript
In JavaScript, the following code:
Copy the code code as follows:
if(true) {
varnum = 10;
}
alert(num);
The result of the operation is a pop-up window 10. So how is the scope of variables limited in JavaScript?
2.1 Function limits variable scope
In JavaScript, only functions can limit the scope of a variable. What does that mean?
That is to say, in JavaScript, variables defined within a function can be accessed within the function, but outside the function
Unable to access. See the following code:
Copy the code code as follows:
var func = function() {
varnum = 10;
};
try {
alert(num);
} catch ( e ) {
alert(e);
}
When this code is run, an exception will be thrown and the variable num is not defined. In other words, the variable defined in the function cannot
Used outside the function, of course it can be used freely within the function, even before assignment. See the following code:
Copy the code code as follows:
var func = function() {
alert(num);
varnum = 10;
alert(num);
};
try {
func();
} catch ( e ) {
alert(e);
}
After this code is run, no error will be thrown, and the pop-up window will pop up twice, undefined and 10 (as for why, I will explain below).
It can be seen from here that variables can only be accessed within a function. Similarly, functions within the function can also be accessed.
2.2 Subdomain accesses parent domain
As mentioned earlier, a function can limit the scope of a variable, so the function in the function becomes a subdomain of the scope. In the subdomain
The code in can access variables in the parent domain. See the following code:
Copy the code code as follows:
var func = function() {
varnum = 10;
var sub_func = function() {
alert(num);
};
sub_func();
};
func();
The result of executing this code is 10. You can see the variable access mentioned above. But when accessing the parent domain in the child domain
The code is also conditional. Such as the following code:
Copy the code code as follows:
var func = function() {
varnum = 10;
var sub_func = function() {
varnum = 20;
alert(num);
};
sub_func();
};
func();
This code has one more "var num = 20;" than before. This code is in the subdomain, so the subdomain will access the parent domain.
There has been a change, the result printed by this code is 20. That is, the num accessed by the subdomain at this time is a variable in the subdomain, not the parent domain.
It can be seen that there are certain rules for access. When using variables in JavaScript, the JavaScript interpreter first
Search the user domain to see if there is a definition of the variable. If so, use this variable; if not, search for the variable in the parent domain.
By analogy, until the top-level scope is still not found, an exception "variable is not defined" will be thrown. See the following code:
Copy the code code as follows:
(function() {
varnum = 10;
(function() {
varnum = 20;
(function(){
alert(num);
})()
})();
})();
After this code is executed, 20 is printed. If "var num = 20;" is removed, then 10 is printed. Similarly, if it is removed again
"var num = 10", then an undefined error will occur.
3. Scope chain
With the division of JavaScript scopes, JavaScript access scopes can be connected into a chained tree structure.
Once the scope chain of JavaScript can be clearly understood, then the variables and closures of JavaScript will be very clear.
The following method uses drawing to draw the scope chain.
3.1 Drawing rules:
1) The scope chain is an array of objects
2) All scripts are level 0 chains, each object occupies one position
3) Whenever you see a function extending into a chain, expand it level by level.
4) When accessing, first look at the current function. If it is not defined, check up the chain.
5) Repeat this until level 0 chain
3.2 Examples
Look at the code below:
Copy the code code as follows:
varnum = 10;
var func1 = function() {
varnum = 20;
var func2 = function() {
varnum = 30;
alert(num);
};
func2();
};
var func2 = function() {
varnum = 20;
var func3 = function() {
alert(num);
};
func3();
};
func1();
func2();
Let’s analyze this code:
-> First of all, the entire code is a global scope and can be marked as a level 0 scope chain. Then there is an array
var link_0 = [ num, func1, func2 ]; // Described here with pseudo code
-> Here func1 and func2 are both functions, so two level 1 scope chains are derived, namely
var link_1 = { func1: [ num, func2 ] }; // Described here with pseudo code
var link_1 = { func2: [ num, func3 ] }; // Described here with pseudo code
-> The first level 1 chain derives from the level 2 chain
var link_2 = { func2: [ num ] }; // Described here with pseudo code
-> The second level 1 chain has no variables defined and is an empty chain, which is expressed as
var link_2 = { func3: [ ] };
-> By integrating the above code, the scope chain can be expressed as:
Copy the code code as follows:
//Described here with pseudo code
var link = [ // Level 0 chain
num,
{ func1 : [ // The first level 1 chain
num,
{ func2 : [ // Level 2 chain
num
] }
]},
{ func2 : [ // The second level 1 chain
num,
{ func3 : [] }
]}
];
-> Represented as an image as
Figure: 01_01 scope chain.bmp
Note: Use js code to express the chain diagram, and it will be very clear when highlighted.
With this scope chain diagram, you can clearly understand how accessing variables is performed:
When you need to use a variable, first search for the variable on the current chain. If you find it, use it directly. No
Search upward; if not found, then search up the one-level scope chain until the 0-level scope chain.
If you can very clearly determine the level of the scope chain to which a variable belongs, then when analyzing JavaScript
It's very easy when it comes to coding and using advanced JavaScript features like closures (at least for me).
3. Variable name promotion and function name promotion
With the scope chain and variable access rules, there is a very difficult problem. Let’s look at the following first.
JavaScript code:
Copy the code code as follows:
varnum = 10;
var func = function() {
alert(num);
varnum = 20;
alert(num);
};
func();
What will be the result of execution? You can think about it, I won’t reveal the answer yet.
Let’s analyze this code first.
There is a level 0 scope chain in this code, which contains the members num and func. Under func, there is a level 1 function.
Domain chain, which contains member num. Therefore, when the function func is called, it will be detected in the current scope
The variable num has been defined, so this variable will be used. However, num is not assigned a value at this time, because the code
The code runs from top to bottom. Therefore, the first print is undefined, and the second print is 20.
Did you get it right?
It is also common in JavaScript to define code at the back and use it at the front like this
Question. At this time, it is as if the variable was defined at the beginning, and the result is like the following code:
Copy the code code as follows:
varnum = 10;
var func = function() {
var num;// It feels like it has been defined here, but there is no assignment.
alert(num);
varnum = 20;
alert(num);
};
func();
This phenomenon is often called variable name promotion. There is also function name promotion. For example, the following code:
Copy the code code as follows:
var func = function() {
alert("Call external function");
};
var foo = function() {
func();
var func = function() {
alert("Call internal function");
};
func();
};
Okay, what does this code look like? Or there should be something different, I won’t leave it to the readers to think!
I’ll give the answer in the next article.
Due to these differences, during actual development, it is recommended to write all variables at the beginning.
That is to say, the variables are defined at the beginning of the function, similar to the provisions of C language. This is also true in js libraries.
This is done, such as jQuery, etc.
4. Summary
Okay, this article mainly explains what JavaScript’s lexical scope is all about, and its explanation.
How to analyze the scope chain and variable access status, let’s leave one last exercise to finish! ! !
See what the result of executing the code below is:
Copy the code code as follows:
if( ! "a" in window ) {
var a = "define variable";
}
alert(a);