Procedure execution
Heap and stack
Heap and stack itself are data structures, heap (linked list structure) and stack (stack structure).
When the program is running, the memory is logically divided into heap memory and stack memory.
-
Stack: the memory of stack structure is relatively small and fast. The operating system will allocate and recycle it automatically.
Features: in and out.
-
Heap: the memory of heap structure is relatively large and slow. It is usually assigned by programmers when they use it. For memory to be reclaimed, it must be released manually.
Features: first in first out (queuing)
This is true in the underlying language. In js, our various memory mechanisms are almost automatic.
execution environment
There are two operating environments for JavaScript:
- Global, global. When JavaScript starts running, the default running environment is the global execution environment.
- Function, function. When a function is called, it enters the execution environment of the function.
Each running environment is often referred to as an execution context.
When the code is executed, a section of stack space is opened up to explain the execution order of the code. This stack is called execution stack.
- When the JavaScript code is executed, the global execution environment will be pushed to the bottom of the stack first. When the function is executed, the function execution environment will be created and the function execution environment will be pushed to the bottom of the stack.
- When the function execution is completed, the function execution environment will pop up from the execution stack and be destroyed (as long as the execution environment is destroyed, a series of things related to it will be destroyed).
- The global execution environment is not destroyed until all code is executed.
Stage of execution environment
- Creation phase (for preparation)
- Global execution environment: it has entered the creation stage since its inception.
- Function execution environment: when a function is called, but before the code is actually executed.
- Execution phase (real execution code)
Scope and scope chain
-
What is scope?
Scope: the scope of the variable.
-
Scope?
Isolate variables. Variables defined outside the function have no relationship with variables defined inside the function.
-
When is the scope determined?
The scope is determined when entering the global execution environment or function execution environment.
-
Scope type?
In ES5, there are two scopes: global scope and local scope (function scope)
ES6 adds block level scope.
When you execute JavaScript, you enter the global execution environment and have the global scope. When you execute a function, you enter the function execution environment and have the scope of a function.
If the execution environment is destroyed, its scope will also be destroyed.
__ Multiple calls to the same function will produce different execution environments, and each call will produce one__ Because the address space allocated by each execution environment is different.
-
Global variable, local variable
-
Global variables: variables defined in the global execution environment. (variables outside the function, global scope)
-
Local variables: variables defined in the local environment. (function internal, function scope)
-
Local variable: it can only work in its own scope and can only be used inside the function, but not outside.
function test(){ var a = 1; var b = 2; console.log(a); } test(); console.log(a);
-
Global variable: it can be used everywhere in the whole program (including inside the function).
var c = 3; function test() { var a = 1; var b = 2; console.log(c); } test(); console.log(c);
Define as few global variables as possible and minimize the permissions of variables.
-
-
Scope chain
Functions can be nested inside functions.
var a = 0; function test() { var a = 1; function test1() { console.log(a);//1 } test1(); console.log('test');//test } test();
The above code outputs 1. Why test is 1 is caused by the scope chain.
Scope is the scope of a variable. Scope chain is used to describe a series of processes of finding variables.
When a function is defined, it will generate an attribute [[scope]] attribute (those with [[]] cannot be accessed). This attribute stores the scope level when the function is defined.
Only when the scope chain is executed: scope chain = current function scope + [[scope]]
The scope is sometimes implemented;
[[scope]] is sometimes defined;
The scope chain is finally generated when it is executed. Scope chain = current function scope + [[scope]]
The current scope of the function is the top of the scope chain, and the global scope is the last end of the scope chain.
If the execution environment is destroyed, the scope chain will also be destroyed.
var defines variables to limit the scope to the nearest function scope. If the variable is not defined in the function, the variable defined in the global scope belongs to the global scope.
-
Lookup procedure for variables used in local scope:
-
Whether there is a formal parameter with the same name in the local scope. If so, use it.
<script> function test(a){ console.log(a); } test(1); </script>
-
Whether there is a function with the same name in the local scope (functions can also be defined inside the function). If so, use it. And can be used before or after definition.
function test(){ /* function a(){} a(); a(); */ a(); function a(){ console.log('a'); } a(); } test();
-
Whether there is a variable declaration with the same name in the local scope. If so, use it (it will be undefined before declaration and value after declaration)
function test() { /* var a; console.log(a); a = 1; console.log(a); */ console.log(a);//undefined var a = 1; console.log(a);//1 } test();
-
If a formal parameter and variable with the same name are used at the same time: the variable will overwrite the formal parameter, the value of the argument will be used immediately under the formal parameter, and the value of the variable will be used under the variable definition.
<script> function test(a){//a=2 /* var a ;//Ignore duplicate declarations console.log(a);//2 a = 1; console.log(a);//1 */ console.log(a);//2 var a = 1; console.log(a);//1 } test(2); </script>
-
At the same time, the formal parameters and functions with the same name are defined: the function will overwrite the formal parameters. It is a function to use immediately under the formal parameters or immediately under the function definition.
function test(a) { console.log(a);//Function body function a() { console.log('a'); } console.log(a);//Function body } test(2);
-
If variables and functions with the same name are defined at the same time: the first line of the function will be the sub function, and the value used under the variable definition will be the value of the variable.
function test() { console.log(a);//function var a = 1; console.log(a);//1 function a() {//Subfunction console.log('a'); } console.log(a);//1 } test();
-
If the formal parameter, function and variable declaration with the same name are defined at the same time: the sub function overrides the formal parameter, the first line of the function will be the sub function, and the variable value will be used under the variable definition.
function test(a) { console.log(a);//function var a = 1; console.log(a);//1 function a() { console.log('a'); } console.log(a);//1 } test(2);
-
If there is no such variable in the local scope, the search starts from the upper level along the scope chain.
- If the upper layer can be found, it will be used.
- If it is not found, continue to find the upper layer until it is found in the global scope. If it is found, use it. If not, report an error.
-
-
The process of setting variables in a local scope:
-
Check whether a variable with the same name is defined in the function. If so, modify the variable in the scope directly.
<script> function test(){ var a = 1; console.log(a);//1 a = 2; console.log(a);//2 } test(); </script>
-
If there is no variable with the same name in this scope, look up the upper layer along the scope chain. If it is found, it is set in the upper layer scope.
function test1(){ var a = 'xyz';//1 2 function test(){ console.log(a);//xyz a = 1; console.log(a);//1 a = 2; console.log(a);//2 } test(); console.log(a);//2 } test1();
-
If it is not found in the end, check whether there is in the global scope. If there is, modify it. If not, declare it.
var a = '000'; function test1(){ function test(){ console.log(a+'!');//000! a = 1; console.log(a+'@');//1@ a = 2; console.log(a+'#');//2# } test(); console.log(a+'$');//2$ } test1(); console.log(a + '%');//2%
For example:
function test1() { function test() { a = 1; console.log(a + '@');//1@ a = 2; console.log(a + '#');//2# } test(); console.log(a + '$');//2$ } test1(); console.log(a + '%');//2%
Summary: the scope chain function is generated only when it is executed, because the scope chain is equal to the current scope + [[scope]]
Current scope: generated when a function is called.
[[scope]] attribute: it exists when the function is defined, even if the function is not called.
<script> var num = 10; function fun() {//[[scope]] - > global scope var num = 20; fun2();//Scope of fun2 + global scope } function fun2() {//[[scope]] - > global scope console.log(num); } fun();//Scope of fun + global scope </script>
In the local environment of fun, you can call fun2 in the global environment. When fun2 executes, find num. at this time, the scope chain of fun2 only contains the execution environment of fun2 + the global execution environment
Data storage in memory
-
Analysis 1:
<script> var a = 100; console.log(a); </script>
Enter the global execution environment. The global execution environment finds that there are variable declarations. Use a space in the stack space to store a=100. When you execute to console.log(a); When searching for the identifier a from the stack memory, and then find its value.
If the variable is a basic data type (String, Number, Boolean, undefined, null), it will open up space to store the identifier in the stack memory, and then store the value of the basic type in the stack memory and correspond to the identifier.
- Analysis 2:
-
Analysis 3:
The value of the reference type is stored in the heap memory. When storing the reference type, a memory address will be given to the heap memory, but the identifier is still in the stack memory. In order to combine the identifier with the real data, the value stored in the stack is the address of the reference type.
Memory addresses start with hexadecimal 0x.
If the variable is a reference type, a space will be opened in the stack memory to store the identifier. The value of the reference type is stored in the heap memory, which corresponds to the memory address. This memory address will be stored in the stack memory to correspond to the identifier.
The lookup variable is related to the execution environment, scope and scope chain, but not to the heap, because it is a lookup identifier, which is stored in the stack.
- Analysis 4
When assigning a reference type, it is assigned an address rather than a value.
Addressing and assignment
- Analysis 5:
-
Analysis 6:
-
Analysis 7:
What is executed at the beginning ~ end of the program:
-
When the program starts to execute, it meets the global execution environment. Create the global execution environment and push it into the execution stack. When the global code is executed, it depends on the things in the global environment.
Global variable: if it is a basic data type, the value is stored in stack memory. If it is a reference type, the data is stored in heap memory and the identifier is stored in stack memory. Then it should correspond to the address in heap memory.
-
When a program encounters a function call, it has its own execution environment, and then pushes its own execution environment into the execution stack.
Local variables: the data storage routine of local variables is the same as that of global variables, but the execution environment is different.
Local variables appear only when the function is executed. After the function is executed, the function environment will be destroyed and the local variables will not exist.
-
After the function call is completed, continue to execute the code in the global environment until all the codes are executed, which means that the program is over, the program is over, and the global environment is finally out of the stack (destroyed)
-
Variable promotion (pre parsing)
Execution environment:
- Creation phase
- Execution phase
Creation stage: put the declaration of variables and functions with var at the top of the current scope. Execution stage: start assigning values and processing other logic at the position where the original code itself should be.
console.log(a); var a = 1; But the actual implementation is not like this, the actual implementation is var a;//undefined declared during creation console.log(a);//At this time, a is used in the execution phase, but the above a has not been assigned, so the printed value is undefined a=1//Re assignment is performed during the execution phase test(); function test(){ console.log('!'); } test(); During actual implementation: function test(){ console.log('!'); } test(); test();
be careful:
-
Whether it is the global execution environment or the function execution environment, each execution environment will promote variables and functions.
-
Only functions declared by function will be promoted. Functions declared by function expressions and function constructors will not be promoted.
<script> /* var foo;//undefined foo();//foo Not a function. If foo does not exist, it is foo not defined foo = function(){ } */ foo(); var foo = function (){ console.log('!!!'); } </script>
-
Function declarations and variables will be promoted, but functions will be promoted first, and then variables (in JS, functions are first-class citizens)
/* function foo(){//A function foo is defined console.log(1); } //Duplicate foo definitions will be ignored. var foo; foo(); foo = function(){ console.log(2); } */ foo(); var foo; function foo(){ console.log(1); } foo = function(){ console.log(2); }
During parsing, the foo() function will be promoted to the front, followed by var foo. However, because the function has been declared, var foo belongs to repeated definition and will be ignored. Then, execute the foo() function to output 1, and then define the function expression foo = function(), so it overrides the previous foo function.
The function has the same name. In the promotion process, the later one overrides the previous one.
Little practice
-
First pit
<script> alert(a); a = 0; </script>
An error is reported. It is not a normal variable definition, and there will be no lifting operation.
-
Second pit
/* var a ; alert(a);//undefined a = 0; alert(a);//0 */ alert(a);//undefined var a = 0; alert(a);//0
-
Third pit
<script> /* function a(){} var a; alert(a); a = 'I am a variable '; alert(a); */ alert(a); var a = 'I'm a variable'; function a() { alert('I'm a function') } alert(a); </script>
-
Fourth pit
<script> /* function a(){} var a; alert(a);//function a++;//NaN alert(a);//NaN a='I am a variable '; alert(a);//I'm a variable */ alert(a); a++;//The function conversion value is NaN. alert(a); var a = 'I'm a variable'; function a() { alert('I'm a function') } alert(a); </script>
-
Fifth pit
-
Sixth pit
-
Seventh pit
-
Eighth pit