The body of the
What is the scope
A scope is a set of rules for determining where and how to look for variables.
Before getting into scope, a quick look at how compilation works: the book (js you don’t know) says that JavaScript is a compiled language. In traditional compiled languages, a piece of source code in a program goes through three steps, collectively known as “compile,” before execution.
- Word segmentation/lexical analysis breaks a string into meaningful code blocks, also known as lexical units.
- Parsing/parsing replaces the lexical unit stream with a number of nested elements that represent the syntax interface of the program, also known as the “abstract syntax tree.”
- Code generation: Translating abstract syntax trees into instructions that machines can recognize.
Understanding scope
Scopes work with compilers and engines to parse code
There’s an example in the book that says var a = 2, first the compiler will split it into two parts, var a and a = 2. The compiler will execute var a at compile time and then go to scope to look for variable A. If a is not already declared in scope, it will declare it in scope. If a already exists, it will ignore var a. The compiler then generates execution code for the a = 2 statement for the engine to perform the assignment. So we usually mentioned the variable promotion, in fact, is the use of the principle of the first declaration after the assignment.
The working mode of the scope
There are two main working models for scopes. The first is the most common, lexical scope adopted by most programming languages (a scope in JavaScript is a lexical scope). The other is dynamic scoping, which is still used by some programming languages (Bash scripts, some patterns in Perl, etc.).
Abnormal situation
For var a = 10, the assignment is to find variable A and assign the value 10 to it. This is the LHS query. The console.log(a) statement, which is actually looking up the value of A and printing it out, is an RHS query.
Why is it important to distinguish BETWEEN LHS and RHS?
In non-strict mode, a global variable is created when the LHS call cannot find the variable, and a ReferenceError is raised when the RHS call cannot find the variable. In strict mode, both LHS and RHS raise ReferenceError when they cannot find a variable.
Lexical scope
Lexical scope is a set of rules about how and where the engine looks for variables. The most important feature of lexical scope is that its definition takes place at the writing stage of the code (assuming eval() or with is not used)
An 🌰
function testA() {
console.log(a); // 2
}
function testB() {
var a = 3;
testA();
}
var a = 2;
testB() lexical scope lettestA in A() refers to A in global scope via RHS, so it prints 2.Copy the code
Dynamic scope
Dynamic scopes only care about where they are called from. In other words, the scope chain is based on the call stack, not the scope nesting in the code.
// Therefore, if JavaScript has dynamic scope, in theory, in the following codetestA() prints 3 when executed.function testA() {
console.log(a); // 3
}
function testB() {
var a = 3;
testA();
}
var a = 2;
testB()
Copy the code
Function scope
Named and anonymous
The book gives an example – the > callback function
setTimeout( function() {
console.log("I've waited so long!)}, 1000)Copy the code
Function expressions can be anonymous, and function declarations cannot omit function names. Anonymous function expressions are quick and easy to write, and many libraries and tools tend to encourage this style of code. But it also has several drawbacks to consider.
- Anonymous functions do not show meaningful function names in the stack trace, making debugging difficult.
- Without a function name, the expired arguments.callee reference can only be used when the function needs to reference itself, such as in recursion. Another example of a function needing to reference itself is when the event listener needs to unbind itself after the event is fired.
- Anonymous functions omit function names that are important to code readability/understandability. A descriptive name lets the code speak for itself.
To address this shortcoming, the book gives advice: name the function expression
setTimeout( function timeoutHandler() {
console.log("I've waited so long!)}, 1000)Copy the code
ascension
Let me ask you a question, is there an assignment or is there a declaration
a = 2; var a; console.log(a); / / 2Copy the code
Is equivalent to
var scope="global";
function scopeTest(){
var scope;
console.log(scope);
scope="local"
}
scopeTest(); //undefined
Copy the code
We’re used to var a = 2; As a statement, which the JavaScript engine does not. It treats var a and a = 2 as two separate declarations, the first for the compile phase and the second for the execution phase.
This means that no matter where the declaration in scope appears, it will be processed first before the code itself is executed. This process can be visualized as all declarations (variables and functions) are “moved” to the top of their scope. This process is called promotion.
So you can see that the declaration comes before the assignment
Look again a small 🌰
foo(); // TypeError
bar(); // ReferenceError
var foo = function bar() {/ /... };Copy the code
This code snippet, when enhanced, is actually understood as the following:
var foo;
foo(); // TypeError
bar(); // ReferenceError
foo = function() { var bar = ... self... / /... };Copy the code
The variable identifier foo() in this program is promoted and assigned to the global scope, so foo() does not cause ReferenceError. But foo is not assigned at this point (it would be if it were a function declaration rather than a function expression). Foo () raises TypeError because a function call on the value of undefined causes an illegal operation. In addition, even if the function expression is named, the name identifier (bar in this case) cannot be used in its scope until it is assigned.
conclusion
I hope everyone can find their own learning methods to re-learn the front end, improve their knowledge architecture ~