Scope is one of the most important concepts in JavaScript. To learn JavaScript well, you need to understand how JavaScript scope and scope chain work. This article is about JavaScript scope and scope chain, hoping to help you learn JavaScript better.

directory

First, javascript scope

1. Global scope
1) Outermost function and outermost variable
2) Variables that are not directly assigned are not defined (global due to variable promotion)
2. Local scope
1) Function scope
2) Caution before ES6 block-level scopes are explained
3. Block level scope

Javascript scope chains

1) How is JavaScript executed?
The analysis phase
Execution phase
Examples of JavaScript execution
2) Scope chain concept
3) Find special instructions for process LHS and RHS query
LHS and RHS features
Examples of LHS and RHS are given
4) Scope chain summary

conclusion

👣 a tail

First, javascript scope


1. Global scope

Objects with global scope can be accessed anywhere in the code, and there are several general situations in JS that have global scope:

1) Outermost function and outermost variable:
var globleVariable= 'global';  // Outermost variable
function globalFunc(){         // Outermost function
    var childVariable = 'global_child';  // Function variables
    function childFunc(){        // Inner function
        console.log(childVariable);
    }
    console.log(globleVariable)
}
console.log(globleVariable);  // global
globalFunc();                 // global
console.log(childVariable)   // childVariable is not defined
console.log(childFunc)       // childFunc is not defined
Copy the code

As you can see from the code above, globleVariable and globalFunc can be accessed anywhere, whereas variables that do not have global scope properties can only be used within their scope.

2) Variables that are not directly assigned are not defined (global due to variable promotion)
function func1(){
    special = 'special_variable';
    var normal = 'normal_variable';
}
func1();
console.log(special);    //special_variable
console.log(normal)     // normal is not defined
Copy the code

While we can declare functions and variables in a global scope as global variables, this is not recommended because it may conflict with other variable names. On the one hand, if we declare a variable using const or let, we will get an error when naming conflicts.

// Variable conflicts
var globleVariable = "person";
let globleVariable = "animal"; // Error, globleVariable has already been declared
Copy the code

On the other hand, if you declare a variable using var, the second declaration of the same variable will overwrite the previous one, which can make your code difficult to debug.

var name = 'front end'
var name = 'xiangxue'
console.log(name);  // xiangxue
Copy the code

2. Local scope

In contrast to global scopes, local scopes are generally accessible only within fixed code snippets. The most common is function scope.

1) Function scope

Variables defined in a function are in the function scope. And the function has a different scope each time it is called. This means that variables with the same name can be used in different functions. Because these variables are bound in different functions and have different scopes, they cannot be accessed from each other.

// Global scope
function test(){
    var num = 9;
    // It can be accessed internally
    console.log("In the test."+num);
}
// Test cannot be accessed externally
console.log("The test outside."+num);
Copy the code

Note:

  • If a variable is defined in a function and the var keyword is not added, the variable is promoted and becomes a global variable.
function doSomeThing(){
    // Avoid this at work
    thing = 'writting';
    console.log('Inside:'+thing);
}
console.log('external:'+thing)
Copy the code
  • Any pair of curly braces {… } all belong to a block, and before ES6, variables defined in block statements would remain in scope where they already existed:
var name = 'Front-end Programmer Growth Guide';
for(var i=0; i<5; i++){
    console.log(i)
}
console.log(External: '{}'+i);
// 0 1 2 3 4 {} External :5
Copy the code

We can see that the variables name and I are sibling scopes.

2) Caution before ES6 block-level scopes are explained

Variable ascension

As defined in MDN, variable promotion claims are handled prior to execution of any code. Declaring a variable anywhere in the code area is the same as declaring it at the very beginning (or at the very top). That is, it looks like a variable can be used before it is declared! This behavior is called “reactive,” or variable promotion, as if the variable’s claim were automatically moved to the top of a function or global code. Take a look at this code:

var tmp = new  Date(a);function f() {
    console.log(tmp);
    if(false) {
        var tmp='hello'; }}Copy the code

This question should be many of you have encountered in the interview, some people will think that the output is the current date. But the correct result is undefined. This is caused by the variable promotion, where it is declared that the content of the definition will not be promoted, the corresponding code after the promotion is as follows:

var tmp = new Date(a);function f() {
    var tmp;
    console.log(tmp);
    if(false) {
        tmp='hello';
    }
}
f();
Copy the code

When console outputs, the TMP variable is declared but not defined. So the output is undefined. Although can output, but does not recommend this method recommended practice is at the time of state variables, are written in the book will be used in variable scope (global scope, or function scope) on top of this code will look more clear, it is easier to see which variables are come from the functional scope, which is from the scope chain

Look at an example:

// var
var name = 'front end';
console.log(name); / / the front
if(true) {var name = 'Front-end Programmer Growth Guide';
    console.log(name); // Front-end programmer growth guide
}
console.log(name); // Front-end programmer growth guide
Copy the code

Var name=’ front-end programmer growth guide ‘is ignored and used only for assignments. Var name=’ front-end programmer growth guide’ is ignored and used only for assignments. This means that the code above is actually the same as the code below.

// var
var name = 'front end';
    console.log(name); / / the front
if(true){
    name = 'Front-end Programmer Growth Guide';
    console.log(name); // Front-end programmer growth guide
}
console.log(name); // Front-end programmer growth guide
Copy the code

The simultaneous occurrence of variables and functions

What happens if both functions and variables are declared? Look at the code below

console.log(foo);
var foo ='i am web';
function foo(){}
Copy the code

The output is function foo(){}, which is the function content

What if it’s the other way around?

console.log(foo);
var foo ='i am web';
var foo=function (){}
Copy the code

The output is undefined

Two kinds of results are analyzed and explained: the first kind: function declaration. Function foo(){}

Another: functional expressions. Var foo=function(){

The second form is the declaration definition of the var variable, so it should be understood that the second form is undefined.

The first form of function declaration, when promoted, is promoted in its entirety, including the function definition! So the first form is equivalent to the following!

var foo=function (){}
console.log(foo);
var foo ='i am web';
Copy the code

The reason is:

  1. Function declarations are promoted to the top;
  2. The declaration is made only once, so the following declaration var foo=’ I am web’ is ignored.
  3. Function declarations take precedence over variable declarations, and function declarations are promoted along with definitions (unlike variables).

Next, after the introduction of block-level scopes in ES6!

3. Block level scope

ES6 added the let and const commands to create block-level scoped variables. Variables declared using the let command are only valid within the code block in which the let command is located.

The syntax of the let declaration is the same as that of var. You can basically use let instead of var to declare variables, but limit the scope of variables to the current code block. Block-level scopes have the following characteristics:

  • Variables are not promoted to the top of the code block and do not allow external access to block-level scoped internal variables
console.log(bar);// Raise the 'ReferenceErro' exception: a variable 'is not defined'
let bar=2;
for (let i =0; i<10; i++){console.log(i)
}
console.log(i);// Raise the 'ReferenceErro' exception: a variable 'is not defined'
Copy the code

In fact, this feature has many benefits. When developers need to check code, they can avoid the accidental use of variables outside the scope, and ensure that variables are not confused but reused, improving the maintainability of the code. As in the example in the code, a variable I used only inside the for loop does not pollute the entire scope.

  • Repeated statements are not allowed

ES6 lets and const are not allowed to be declared repeatedly, unlike var

// var
function test(){
    var name = 'koloa';
    var name = 'Programmer growth is north';
    console.log(name); // Programmer growth refers to north
}

// let || const
function test2(){
    var name ='koloa';
    let name= 'Programmer growth is north';
    // Uncaught SyntaxError: Identifier 'count' has already been declared
}
Copy the code

It’s important to see if you sense the emergence of block-level scope here.

Javascript scope chains

So before we go into scope chains, let’s just talk a little bit about how JavaScript works, okay?


1) How is JavaScript executed?

The analysis phase

The javascript compiler compiles and generates code for analysis

  • Analytic function parameter
  • Analysis variable declaration
  • Analytic function declaration

At the core of the analysis phase, an AO(Active Object) is created after the analysis is complete (that is, the moment the next function executes).

Execution phase

Analysis Phase After the analysis is successful, the Active Object (AO) is sent to the execution phase

  • The engine asks the scope if it has this variable called X
  • If the scope has an X variable, the engine uses it
  • If the scope is not there, the engine continues to look (up to the upper scope), and if the variable is not found at the end, the engine throws an error.

The core of the execution phase is to find, specific how to find, later will explain LHS query and RHS query.

Examples of JavaScript execution

Take a look at this code:

function a(age) {
    console.log(age);
    var age = 20
    console.log(age);
    function age() {}console.log(age);
}
a(18);
Copy the code

First, enter the analysis phase

As mentioned earlier, the moment the function runs, create an AO (Active Object).

AO = {}
Copy the code

Step 1: Analyze function parameters:

Formal argument: ao.age =undefinedArgument: ao.age =18
Copy the code

Step 2, analyze variable declarations:

// Line 3 has var age
Age = 18; // Do nothingThe AO. Age =18
Copy the code

Step 3, analyze function declaration:

// Line 5 has the function age
// function age(){} is paid to ao.age
AO.age = function age() {}
Copy the code

Note in function declaration: If there is an attribute on the AO with the same name as the function name, it will be overwritten by this function. But here’s the case

var age = function () {
       console.log('25');
  }
Copy the code

Declared functions do not override attributes of the same name in the AO chain

Enter execution stage

Analysis phase After the analysis is successful, it will give the AO(Active Object) to the execution phase, the engine will ask the scope, find the process. So the code above in the AO chain should initially be

AO.age = function age() {}
/ / after
AO.age=20
/ / after
AO.age=20
Copy the code

So the final output is:

function age(){}20
20
Copy the code

2) Scope chain concept

Having seen a complete javascript function execution, let’s talk about the concept of scope chains. Each JavaScript function executes by looking for the corresponding property value in the AO it creates. If you can’t find it, look for the parent function’s AO. If you can’t find it again, look for the AO at the next level up until you find the big boss:window. This “AO chain” is the scope chain in JavaScript.

3) Find special instructions for process LHS and RHS query

The terms LHS and RHS are used when the engine queries variables. It’s also clearly described in Js you Don’t Know.

LHS = Variable assignment or write to memory. Imagine saving a text file to your hard disk. RHS = Variable lookup or read from memory. Imagine opening a text file from your hard drive. Learning Javascript, LHS RHS

LHS and RHS features
  • Is queried in all scopes
  • In strict mode, the engine throws ReferenceError when the desired variable is not found.
  • In non-strict mode, LHR is slightly special: a global variable is automatically created
  • When the query succeeds, TypeError will be raised if unreasonable operations are performed on the value of a variable, such as a function call on a value that is not of a function type
Examples of LHS and RHS are given
function foo(a) {
    var b = a;
    return a + b;
}
var c = foo( 2 );
Copy the code

Look directly at the engine in scope to find this procedure: LSH (write to memory) :

c=, a=2(Implicit variable assignment), b=Copy the code

RHS(Read memory) :

Read the foo (2), = a, a ,b
(returnWhen a + b, we need to find a and B.Copy the code

4) Scope chain summary

conclusion

  • A scope chain is a list of multiple scopes.
  • The scope chain is stored on a function.
  • A scope chain contains references to all scope objects available to a function, and thus all variables available to the function.
  • The scope chain controls the order in which variables are used — local before global

👣 a tail

If you think the article is good, please also help to like it and save it into the folder. Your support is the power of writing.

🎶# English daily come a #

“What makes life dreary is the want of motive.”

What makes life dreary is the want of motive.