If you are not familiar with scope, lexical scope, then you should read this article, which is the key to understanding closures!

What is the scope?

Understanding scope

To facilitate the understanding, the author use the dialogue in a way that explain engine: responsible for js program compilation and execution of the compiler: responsible for parsing and code generation dirty work scope: responsible for the collection and maintenance of all statement identifier some queries, and implementation of a set of very strict rules, to determine the currently executing code access identifier

Let’s say we have var= 1; It looks like a declaration, but the engine dude doesn’t see it that way. The engine sees two different declarations, one run by the compiler at compile time and the other handled by the engine at run time. Var a =1 will decompose into var a; a=1

  • First, var a; The compiler asks the scope if a exists; if it does, the compiler ignores it; if it doesn’t, it asks the scope to declare a new variable in the collection of the current scope, named A
  • The compiler then generates run-time code for the engine to handle the a=1 operation. When the engine runs, it will ask the scope parent if a exists, and if it does, it will use it. If it does not, the engine will continue to look for it. An assignment is performed if it is found, and an exception is thrown if it is not

In the process of engine search, there are two types of query

LHS and RHS

  • An LHS query is performed when a variable appears on the left side of an assignment operation and an RHS query is performed when a variable appears on the right
  • LHS: Who is the target of the assignment operation. RHS: Who is the source of the assignment operation

Take a look at the code below

function foo(a){
    console.log(a);/ / 1
}
foo(1);
Copy the code

foo(…) The call to the function requires an RHS reference to foo, which means “go find the value of foo and give it to me” with one detail that is easily overlooked: a=1

This happens when 1 is passed to foo (), which is assigned to A, and in order to (implicitly) assign a value to a, there is an LHS query and an RHS reference to A, which is passed to console.log(). Console.log () itself does an RHS query on the console object to check the value and see if there is a method called log.

Nesting of scopes

Look at the following code

function(a){
    console.log(a+b);
}
var b=2;
foo(1);  / / 3
Copy the code

Where RHS queries on b cannot be done inside function foo, but can be done in a parent scope

Engine: the scope of the foo bro, are you there is b, I for RHS query scope: no no, don’t bother me pick up hot chicks engine: foo superior scope laoge (global scope), did you saw b, I want to give him the RHS query scope: saw saw, in the sleeping, I show it to you!

Traversing nested scopes: The search starts at the current scope and works its way up to the global scope, stopping whether it is found or not

Lexical scope

Simply put, lexical scope is the scope of a definition at the lexical stage. In other words, the lexical scope is determined by where you write the variable and block scopes when you write the code, so the lexical analyzer will keep the scope constant when it processes the code (most of the time)

function fn(a){
    var b = a * 2;
    function fn1(c){
        console.log(a,b,c);
    }
    fn1(b*3);
}
fn(2);     / / 2, 4, 12
Copy the code
  1. First, the outermost global scope has only one identifier: fn.
  2. The second scope is the one created by FN, including a, fn1, and b
  3. The third scope is the one created by fn1 and contains: c

Scoped bubbles are contained hierarchically, depending on where the corresponding scoped block code is written.

Scope of search will find the first match in the identifier to stop, in the multilayer nested scopes can define the identifier with the same name, called “cover” “(internal identifier has covered the external identifier), if there is no shelter, would have been to the superior will search until I find the outermost scope to stop. Note: * * * * global variable will automatically become a global object, so can not directly through the global object lexical name, but indirectly through to the global object attribute references to access it (window. A), by this technology can be accessed by the same name is Shadowed variables are global variables, but not a global variable is obscured cannot access to.

Function scope

A scope in a function

Function scope meaning: Global variables belonging to this function can be used and reused throughout the scope of the function. (Actually it can be used in nested scopes.)

function fn(a){
    var b=1;
    function fn1(){
        / /...
    }
    var c = 3;
}
Copy the code

In this code snippet,fn’s scoped bubble contains identifiers A, B, C, fN1. The variable or function represented by this identifier is attached to the scoped bubble regardless of where the identifier declaration appears in the scope. Since a, B, C, and fn1 are all in the scope bubble of fn(), these variables cannot be accessed externally, but they can be accessed inside fn(), as well as in fn1()

Hide the internal implementation

function fn(a){
    b = a+fn1(a*2);
    console.log(b*2);
}
function fn1(a){
    return a-1;

}
var b;
fn(2);  / / 10
Copy the code

In the above code snippet, variables B and fn1() should be the private contents of the internal concrete implementation of fn(), giving access to the external scope is unnecessary and dangerous. If inadvertently used, it will cause a great deal of trouble, so that the applicable conditions are exceeded. The above code can be modified as follows:

function fn(a){
    function fn1(a){
        return a-1;
    }
    var b;
    b=a+fn1(a*2);
    console.log(b*2)
}
fn(2);  / / 10
Copy the code

This makes both B and FN1 inaccessible from the outside, leaving functionality and effects intact, but privatizing the content by design.

To avoid conflict

function fn(){
    function fn1(a){
         i =3; // Modify I in the scope of the for loop
         console.log(a+i);
    }
    for( var i=0; i<10; i++){ fn1(i*2);      // Infinite loop}}Copy the code

The assignment expression I =3 inside fn1() accidentally overwrites I in the for loop. I is fixed at 3, less than 10, causing an infinite loop

Block scope

for(var i=0; i<10; i++){console.log(i);
}
Copy the code

We define I in the header of the for loop, usually only in the context of the inside of the for loop, but I is bound to the outer scope

So let’s look at this code

var f=true;
if(f){
    var fn = f*2;
    fn = something(fn);
    console,log(fn);
}
Copy the code

The fn variable is only used in the context of an if declaration, and it would be nice to declare it inside an if block, but! When using var to declare a variable, it is written the same everywhere, they all end up outside the scope, so this is just a pseudo-block scope with a more readable style. To ensure that fn is not used accidentally, it is probably a matter of self-awareness…

In ES6, block scope has been addressed!!

let

The let keyword binds variables to any scope they are in (usually {… } inside), in other words, let implicitly hijacks the block scope for its declared variables

More believe that can see my previous post understanding var let the difference between const, here but many here!

Let’s look at the for loop

for(let i=0; i<10; i++){console.log(i);
}
console.log(i);//ReferenceError
Copy the code

The let in the header of the for loop not only binds I to the block of the for loop, it actually rebinds it to each iteration of the loop, ensuring that the value at the end of the last iteration of the loop is reassigned as interpreted in code:

let j;
for(j=0; j<10; j++){let i=j;
    console.log(i);
}
Copy the code

try/catch

try{
    undefined(a);// Create an exception
}
catch(err){
    console.log(err);// Normal execution
}
console.log(err);  //ReferenceError:error not found
// Err only exists inside the catch clause, and an error is thrown when an external reference is attempted!!
Copy the code

conclusion

  1. A scope is a set of rules for determining where and how to look for variables (identifiers). An LHS query is used if the purpose of the lookup is to assign a value to a variable, and an RHS query is used if the purpose is to obtain the value of a variable.

  2. Unsuccessful LHS references result in the automatic implicit creation of a global variable (in non-strict mode), with the change using the target of the LHS reference as an identifier. Unsuccessful RHS references cause ReferenceError exceptions to be thrown

  3. Lexical scope means that the scope is determined by the position of the function declaration at the time the code is written. The lexical phase of compilation basically knows where and how all identifiers are declared, so that it can predict how they will be looked up during execution

  4. Functions are the most common unit of scope in JS. Essentially, declaring variables or functions inside a function is hidden in its scope, but functions are not the only unit of scope. Block scope means that variables and functions can belong not only to the scope they are in, but also to a code block.

  5. As of ES3, try/catch structures have block scope in catch clauses.

For readers:

This is the end of the article, thank you for reading, meet is predestined relationship, if you help please praise yo, your praise is my motivation!!

Next: Here’s an article to make sense of closures