Scope boost

Scope

  • First of all, scope is a set of rules for determining where and how to find variables (identifiers). If the purpose of the search is to assign a value to a variable, the LHS query will be used. If the purpose is to obtain the value of the variable, the RHS query will be used. The assignment operator causes LHS queries. = Operators or operations that pass parameters when calling a function will cause a copy operation in the associated scope.

Compiling principle

  1. JS is a compiled language. In the traditional process of compiling languages, a piece of source code in a program will go through three steps before it is executed, which is collectively called "compilation".
    • Word segmentation / lexical analysis. This process breaks up a string of characters into (for a programming language) meaningful code blocks, which are called tokens. For example: var a = 2; will be divided into var, a, =, 2,;.
    • Parsing / grammar analysis. This process is to transform the stream (array) of lexical units into a tree composed of elements nested one by one and representing the program syntax structure. This tree is called an "abstract syntax tree".
    • Code generation. The process of converting AST into executable code is called code generation.

Understanding scope

  1. The engine can create and store variables as needed, and it is responsible for the compilation and execution of the entire JavaScript program from start to finish.
  2. Compiler, responsible for grammatical analysis and code generation and other dirty work (compilation principle)
  3. The scope is responsible for collecting and maintaining a series of queries composed of all declared identifiers (variables), and implementing a very strict set of rules to determine the access rights of the currently executed code to these identifiers.
  4. The variable assignment operation will perform two actions. First, the compiler will declare a variable in the current scope (if it has not been declared before), and then the runtime engine will look for the variable in the scope. If it can be found, it will It is assigned.

translater

  1. The compiler generated code in the second step of the compilation process. When the engine executes it, it will use the lookup variable a to determine whether it has been declared. The search process is coordinated by the scope, but the engine performs such a search, which will affect the final search result.
  2. The engine will query the variable a for LHS. Another lookup type RHS.
  3. LHS search is to try to find the container of the variable itself, so that it can be assigned to it, which is understood as "who is the target of the assignment operation". RHS query and simple search, the value of a variable is the same, understood as "who is the source of the assignment operation".
  4. The JavaScript engine will first compile the code before it is executed. During this process, a declaration like var a = 2 will be broken down into two separate steps:
    • First, var a declares new variables in its scope. This time at the very beginning, before the code is executed.
    • Next, a = 2 will query (LHS query) the variable a and assign it a value.
  5. The compiler can process declarations and worthy definitions at the same time as the code is generated.

Scope nesting

  1. When a fast or function is nested in another block or function, scope nesting occurs.
  2. Rules for traversing nested scope chains: The engine starts looking for variables from the current execution scope, and if it cannot find it, it continues to look up one level. When reaching the outermost global scope, the search process will stop whether it is found or not.

abnormal

  1. If the RHS query cannot find the required variable in all nested scopes, the engine will throw a ReferenceErrer exception.
  2. When the engine executes the LHS query, if the target variable cannot be found in the top level (global scope), a variable with this name will be created in the global scope and returned to the engine, provided that the program runs in a non- " Strict Mode ". In "strict mode" the engine will throw a ReferenceErrer exception.
  3. If the RHS query finds a variable, but you try to perform unreasonable operations on the value of the variable, such as trying to make a function call on a value of the fee function type, or referencing the attribute in the value of the null or undefined type, which engine TypeError will be thrown.
  4. ReferenceErrer is related to the failure of scope discrimination, while TypeError means that the scope discrimination is successful, but the operation of the result is illegal or unreasonable.

Lexical scope

"Scope" is defined as a set of rules used to manage how the engine searches for variables based on the identifier name in the current scope and nested sub-scopes.

Lexical stage

  1. The first working stage of most standard language compilers is called lexical words (also called lexicalization). The lexicalization process will check the characters in the source code, and if it is a stateful parsing process, it will also give the word semantics.
  2. The lexical scope is the scope defined at the lexical stage. Lexical scope is determined by where you write variables and block scope when you write code, so when the lexical analyzer processes the code, it will keep the scope unchanged (in most cases).

Find

  1. Scope lookup will stop when the first matching identifier is found. Identifiers with the same name can be defined in multiple layers of nested scopes, which is called "shadowing effect". Aside from the shadowing effect, the scope scares always start from the innermost scope in which it is running, step by step outward or upward, until it directly encounters the first matching identifier.
  2. No matter where the function is called, and no matter how it is called, its lexical scope is only determined by the position where the function is declared.

Deceptive lexical

  1. There are two mechanisms in JavaScript to achieve the purpose of "modifying" (or deceiving) lexical scope at runtime. However, deceiving lexical scope will cause performance degradation, and the engine cannot be used to optimize the search at compile time, because the engine can only carefully consider that such optimization is invalid.

  2. The eval (...) function in javascript can accept a box of strings as parameters, and the content in it is code that seems to exist at this position in the program at the time of writing. When executing the code after eval (...), the engine does not "know" or "care" that the previous code is inserted in a dynamic form, and the lexical scope environment is modified. The engine will only perform lexical scope lookups as usual.

    function foo(str,a){
        eval(str);//欺骗console.log(a,b);
     }
    val b = 2; 
    foo("var b = 3;",1);//1,3
    
  3. eval (...) is usually used to execute dynamically created code.

with

  1. with is usually used as a shortcut to repeatedly refer to multiple attributes in the same object, without having to repeatedly refer to the object.
  2. with can say that an object with no or multiple attributes is treated as a completely isolated lexical scope, so the attributes of this object are also treated as lexical identifiers defined in this scope.
  3. If the eval (...) function accepts code that contains one or more declarations, it will modify the lexical scope it is in, and the with statement actually creates a brand new lexical scope based on the object you pass it .
  4. eval (...) and with will be affected (restricted) by strict mode. with is completely forbidden, and on the premise of retaining core functions, introduction or unsafe use of eval (...) is also prohibited.

Function scope and fast scope

Function scope

The meaning of function scope means that all the connecting beams belonging to this function can be used and reused within the scope of the whole function (in fact, it can also be used in nested scope). This design is very useful, can make full use of javascript variables can change the "dynamic" characteristics of the value type as needed.

Hide internal implementation

  1. Picking an arbitrary piece of code and then wrapping it with a function declaration actually hides the code.
  2. The actual result is that a scope bubble is created around this code fragment, which means that any declaration (variable, function) soy milk in this code is bound in the scope of this new innovative packaging function, not the previous In the scope. In other words, we can wrap variables and functions in the scope of a function, and then use this scope to "hide" them.
  3. Most of the "hidden" variables and functions are applied from the principle of least privilege, which is also called the principle of least authorization or least exposure.

Conflict avoidance

Another benefit of variables and functions in the "hidden" scope is the avoidance of conflicts between identifiers of the same name. Two identifiers may have the same name but have different uses, and may unintentionally cause naming conflict . Conflicts can cause the values ​​of variables to be accidentally overwritten.

Function scope

  1. The easiest way to distinguish between function declarations and expressions is to see where the function keyword appears in the declaration (not just a line of code, but the position in the entire declaration). If function is the first word in the declaration, then it is a function declaration, otherwise it is a function expression.
  2. The most important difference between function declarations and function expressions is where their name identifiers will be tied. (function foo () {...}) The function expression means that foo can only be accessed in the position represented by ..., not the external scope. The foo variable name is hidden in itself, thinking that it will not unnecessarily pollute the external scope.

Anonymous and named

setTimeout(function(){
        console.log('I waited');
 },100);
  1. This is called an anonymous function expression because function () ... has no name identifier.
  2. Disadvantages of anonymous functions:
    • Anonymous functions do not display meaningful function names in the stack trace, making debugging difficult.
    • If there is no function name, only the expired arguments.calles reference can be used when the function needs to refer to itself.
    • Anonymous functions omit function names that are important for code readability / understandability. A descriptive name can make the code self-explanatory.
  3. Always name function expressions: add a name after function ()

Execute function expression immediately

  1. Since the function is enclosed within a pair of () brackets, it becomes an expression. You can immediately execute the function by adding another () at the end, such as (function foo () {...}) (). The first function becomes an expression, and the second () executes this function.

  2. IIFE: stands for immediate execution of function expressions.

  3. Compared with the traditional IIFE, there is another improved form: (function () {…} ()). These two formal functions are consistent.

  4. Another very common advanced usage of IIFE is to treat them as function calls and pass in parameters.

     var a = 2;
     (function IIFE(global){
         var a = 3;
         console.log(a);//3
         console.log(global.a);//2
     })(window);
     console.log(a);
    

Another application scenario for this pattern is to resolve exceptions caused by the default value of the undefined identifier being overwritten by errors (although not common). Speak of a parameter named undefined, but no value is passed in at the corresponding position, so as to ensure that the value of the undefined identifier in the code block is really undefined.
5. Another use of IIFE is to reverse the running order of the code, put the required functions in the second place, and pass them in as parameters after the IIFE is executed.

Block scope

  1. width is also an example of block scope (a form of block scope). Scopes created from objects with with are only valid in the with statement and not in the external scope.

  2. The ES3 specification of javascript stipulates that the try / catch clause will create a block scope, in which the declared variables are only valid within the catch.

     try{
         undifined();//执行一个非法操作来强制制造一个异常
     }
     catch(err){
         console.log(err);//能够正常执行!
     }
     console.log(err);//ReferenceError
    
  3. In order to avoid unnecessary warnings of static inspection union errors when two or more catch clauses in the same scope use the same identifier name error variables, many developers will name the catch parameters as err1, err2, etc. . Some developers simply shut down the static check tool to check for duplicate variable names.

let

  1. The let keyword can bind variables to any scope (usually {…} inside). In other words, let implicitly hijacks the block scope in which the variable declared by let.

  2. The act of attaching variables to an existing block scope with let is implicit. The displayed code is due to implicit or some delicate but unclear code. The following is the display code:

     var foo = true;
     if(foo){
         {//显示代码块
             let bar = foo * 2;bar = something(bar);
             console.log(bar);
         }
     }
    
  3. As long as the declaration is valid, you can use {...} brackets anywhere in the declaration to create a block for let to bind. In this example, a block is explicitly created inside the if statement. If it needs to be refactored, the entire block can be easily moved without affecting the position and semantics of the external if statement.

const

ES6 also introduced const, which can also be used to create block-scope variables, but its value is fixed (constant). Any subsequent attempt to modify the worthwhile operation will cause an error.

Promote

The compiler strikes again

  1. Part of the job in the compilation phase is to find all the declarations and associate them with the appropriate scope.
    a = 2; var a; console.log (a); // will output 2
  2. var a = 2; will actually be seen as var a; and a = 2; the first definition declaration is made during the compilation phase. The second assignment statement will be left in place for execution. That is, declare first and then assign values.
  3. This means that wherever the declaration in the scope appears, it will be processed before the code itself is executed. This process can be visually imagined as all declarations (variables and functions) will be "moved" to the top of their respective scopes. This process is called promotion.
    4. Note that each scope will be promoted.
    5. The declaration itself will be promoted, and assignment operations including the assignment of function expressions will not be promoted.

Function first

1. Both function and variable declarations will be promoted. However, it should be noted that there is a detail (this detail can appear in code with multiple "duplicate" declarations) that the function will be promoted first, and then the variable.

    foo();//1 var foo; 
    function foo(){
        console.log(1);
    }
    foo = function(){
        console.log(2);
    };//会输出1而不是2
  1. Although repeated var declarations will be ignored, the function declarations that appear in the back cover the previous function declarations.

The definition and examples of this article are taken from:

  • "JavaScript You Didn't Know"
Published 17 original articles · praised 0 · visits 771

Guess you like

Origin blog.csdn.net/CandiceYu/article/details/89136613