An article to understand var, let, const, temporary dead zone

Start the growth journey of Nuggets! This is the Nth day of my participation in the “Nuggets Daily New Plan·February Update Challenge”, click to view the event details

This article briefly introduces the basic knowledge. There will be further extensions in the future.

Characteristics of variables in js

js variables are loosely typed. Variables can be used to hold any type of data. So js is also called a weakly typed language.

Definition and access of variables

Simply talk about the scope

What is scope, in simple terms, is the area where the variable works, can be accessed, and used.

Grammar

Define

The storage location of the value of the variable

When a variable is declared, space is requested from the stack to store the value of the variable.

Use keywords

Variables can be defined using three keywords: var, let, and const. The latter two keywords are only available since ES6. It is recommended to use only the latter two, not the first one. Of course compatibility is another consideration.

Keywords to define variables variable identifier name [[ = initial value], second variable name [ = initial value 2], variable 3 [ = initial value 3], ...];

The content enclosed in square brackets is optional content, and ... means repeated syntax.

Multiple variables can be declared at the same time by separating them with commas.

variable = initial value is equivalent to assigning an initial value to the variable. When the variable is accessed for the first time, if the variable has not been changed before, then the initial value is obtained. Such an operation is called initialization.

If the initialization step is omitted, the obtained value is undefined, which means that the variable has not been initialized and the value is undefined.

For example

let a = 3, b, c = 4; This generates 3 variables a, b, c, the initial values are 3, undefined, 4 respectively.

Do not use keywords

Directly assign a value to an identifier that has not been defined as a variable before or has become invalid after definition. Then when the assignment statement is executed, the identifier will represent a global variable [you can know the name first, and the specific understanding requires scope knowledge].

From this moment on, the variable can be accessed anywhere downwards, even if your variable is defined in a block, I can also access it outside the block.

However, if the variable is accessed before the assignment statement, an error will be reported.

At this time, the scope of the variable is called global scope

console.log(m);//Unable to access, an error will cause the entire program to terminate, and the following statement will not be executed
m = 109;
console.log(m);//Delete the statement that reported the error above and delete it, the statement will be executed, and access to

Note:

When this syntax is placed inside a function, a global variable is still created instead of a local variable. It’s just that the variable will not be created until the function is actually executed. When the function is executed, it will be created. Only later code can access this variable.

This is because js is an interpreted language. It can be roughly regarded as parsing a sentence of code and executing a sentence. Of course, this is not accurate, but it can be understood in a simple way. Therefore, before the function is executed, the global variable cannot be known by the browser, and it is not created.

function test() {
    m = 10;
}
//This line and the above code, except inside the test function, cannot access m, m has not been created
test();//After this line of code is executed, you can access m

var

Variables declared with this keyword have the following characteristics:

The declared variable is a local variable or a global variable:

If the variable is defined in a function, then the variable will be a local variable belonging to the function. It is accessible inside the function. But it doesn’t work outside. At the same time, it also means that the variable will be destroyed when out of this function. Next time the function is accessed, a new variable with the same name will be created. instead of the original. But defined in the outermost global scope, it becomes a global variable.

Note: What is mentioned here is that the variable is defined in the function, not in the function or block.

function a() {<!-- -->
    var x = 1;
    console.log(x);//When the function is executed, the statement will output x
}
a();//Output the value of x, which is 1. It means that x can be accessed inside the a function
console.log(x);//report error

Scope Hoisting:

We know that when we access an undefined variable, he will report an error. But the code below seems to violate common sense.

console.log(a);//no error and output undefined
var a = 1;
console.log(a);//1

It stands to reason that if I explain a line of code and execute a line of code, I can only know the variable after defining the variable. Then why can it be accessed in the front after using the var definition?

This is because js will increase the scope of variables defined using var, and divide var a = 1; into two parts: var a; with a = 1;. And put var a; at the front of the block where a is defined [we say that the outermost code is in a synchronous code block, although there are no curly braces, but also see make a block]. And leave a = 1; in place.

So the code above can be considered equivalent to the code below.

Note: Variable promotion [scope promotion] will only promote the declaration of the variable, and the initialization assignment statement will remain in place. Therefore, in the area from the beginning of the block to the middle of the declaration part, the value of the variable is undefined

var a;
console.log(a);//no error and output undefined
a = 1;
console.log(a);//1

Similarly, the following two codes have the same effect:

function a() {
    console. log(x);
    var x = 1;
    console. log(x);
}
function a() {
    var x;
    console. log(x);
    x = 1;
    console. log(x);
}

The scope of variables defined by

is function scope or global scope.

var is a variable defined within a function when the variable defined by var is function scoped. The variables defined by him can be accessed from the beginning of the function to the end of the function definition.

When the variable defined by var is of global scope, var is the variable defined in the outermost synchronized code block. It can be accessed anywhere in the code.

If the declared variable is in the outermost synchronous code block [also called the global scope], it will be used as a property of the window object

literal meaning.

When the variable definition statement is placed in the global scope, it will be mounted on the variable object of the global context [here, we will understand the context later], and the variable object of the global context can be accessed through the window.

So it will be used as a property of window.

Redundant declarations are allowed

That is, var is allowed to define multiple variables with the same name.

You can understand it as: the statement defined by var is divided into two parts: var identifier; and identifier = initial value;. The first part is mentioned at the front of the function, and the overlapping ones are merged. The second part stays in place.

So it is equivalent to a variable being constantly transformed in different positions.

var a = 1, a = 2;
console.log("Result");
console.log(a);//output 2
var a = 3;
var a;
a = 1;
var a;
console.log(a)//output 1

Variables defined in non-function blocks will permeate outside the loop

For blocks that are not functions, variables defined within var will seep out of the block

{
    var i = 10;
}
// equivalent to
var i;
{
    i = 10;
}

Let me explain here, like while, for and do while are all loop statements, don’t think of it as a function. In these statements, whether it is the header or the content in the execution block [for example, the for loop head is inside the for brackets, and the code inside {} is the execution block] are equivalent to being in a block.

for(let i; i < 10; i ++ ) {<!-- --> console.log(i); }
//In terms of functional analysis, it can be said to be:
{<!-- -->
    let i;
    Judgment i<10
    console. log(i);
    i + +
}

Emphasis: It is equivalent to a statement that executes a specific function wrapped by a block, not wrapped by a function.

Then it proves that in the for loop, the variables defined in the header or in the execution code block will overflow.

For example:

for(var i = 0; i < 5; i ++ ) {<!-- -->
    console. log(i);
}
console. log(i);

After outputting 1, 2, 3, 4, 5, it will still output 5 instead of reporting an error.

In fact, it is equivalent to the following code:

var i;
for(i = 0; i < 5; i ++ ) {<!-- -->
    console. log(i);
}
console. log(i);

let and temporary dead zone

Variables named using let have similar characteristics to var. But [there are 5 differences below, the only 2 in common can be said to be the syntax of the definition and the defined variables can be local or global variables]

No scope hoisting.

And the area from the beginning of the block to the position where this variable is defined is called temporary dead zone.

Variables defined by let are block-level scope.

According to the concept of scope. Because the accessible areas of variables defined by var and let are different.

So the scope of the variable defined by let is naturally different from the scope defined by var.

Block-level scope: Variables can be accessed from the point of definition to the end of the block, but not elsewhere.

Redundant declarations in the same block are not allowed.

Literally.

First, let is not allowed to define multiple variables with the same identifier in the same block.

Moreover, if there is a global variable defined without an identifier or a variable defined by var, which has the same identifier as the variable defined by let and is in the same block, an error will be reported.

But Nested repeating definitions are allowed. [Declaration and definition in js are the same thing] [The following theories come from the Red Book]

Because the js engine [that is, the one responsible for executing js code] will record: the identifier declared or used and the block scope where the identifier is located.

And do a comparison check. In the duplicate checking process, only when the block scopes are different but the identifiers are the same will the redundant definition error be reported.

Like let a = 1; a = 3; In this code, these two a are the same block scope.

And let a = 2, a = 3; In this code, these two a are different block scopes, because the positions of the declarations are different, so the starting position of the block scope of the variable Different, block scoping itself is naturally different. So it will report an error.

So if it is possible to define the same variable in different blocks, no error will be reported.

But Which one should be used when using multi-level nested and repeatedly defined variables?

This phenomenon is called scope coverage. In fact, listening to the name can probably guess which one will be used in the end.

The outer scope is covered by the inner scope. The ownership of the currently repeated area is naturally not the covered scope, but the covered one. And who uses the variable naturally depends on which scope the current location is in.

function a() {<!-- -->
    let a = 1;
    //The access to a below is to access a variable instead of a function, which is also a scope coverage.
    console.log(a);//output 1
    function b() {<!-- -->//If it is changed to a, an error will also be reported. same redundant definition
        //console.log(a); will report an error, which is also a redundancy problem. The usage is also recorded
        let a = "s";
        console. log(a);
    }
    b();//output s
}
a();//Execute the above function.

Define variables in the global scope, variables will not be used as window properties

Literally, the variable defined by let will not be mounted on the variable object of the global context. But it is still defined in the global scope, so the variable can be accessed from the global definition position to the global end.

Variables defined in non-function blocks will not leak outside the loop

Unlike var, variables defined in let blocks do not leak out. It is equivalent to the code block defined in the loop body of the for loop.

for (let i = 0; i < 5; i ++ ) {<!-- -->
    console. log(i);
}
console.log(i);//error reporting
//Equivalent to the code below
while(true) {<!-- -->
    let i;
    if (i < 5) {<!-- -->
        console. log(i);
    }
    else
        break;
    i + + ;
}
console. log(i);

A difference like this is not worth mentioning if you simply use a for loop. But if you use the closure function to refer to the iteration variable i in the for loop, something will go wrong.

  • The most typical example is this: [If you don’t understand closures, just look at the results. When we introduce closures in the future, we will bring up the old things again. 】
for(var i = 0; i < 5; i ++ ) {<!-- -->
    setTimeout(()=>console. log(i), 4);
}
//Finally output 5 5s, which is equivalent to the following code
var i;
for(i = 0; i < 5; i ++ ) {<!-- -->
    setTimeout(()=>console. log(i), 4);
}

setTimeout is a delay function, the first parameter is the callback function [function to be executed], and the second parameter is the delay time [unit ms]. Indicates how long to delay executing the function.

Because the closure function will extend the life cycle of the variable. So the lifetime of i will be extended. When the callback of the setTimeout function is executed [that is, the first parameter], i is still the layer when the setTimeout function was called at that time i of the for loop. But because each layer of for loop actually uses the same variable. The callback is executed after a delay, and the for loop has already finished running when the callback is executed. So the final output will be the value of i, the only iterative variable after 5 cycles–5.

And if let, there is no such problem.

for (let i = 0; i < 5; i ++ ) {<!-- -->
    setTimeout(()=>console. log(i), 4);
}
//Equivalent to the code below
while(true) {<!-- -->
    let i;
    if (i < 5) {<!-- -->
        setTimeout(()=>console. log(i), 4);
    }
    else
        break;
    i + + ;
}

Since each layer of loop is a new variable. So the callback is referring to a different variable. The output is naturally what we expect 0,1,2,3,4

  • The second example is a BUG in my project: For details, see Thinking about eval and let caused by a BUG in the jQuery project

const

The effect and characteristics of let are almost the same.

The only difference is: const variables must be initialized when they are defined. Furthermore, after the definition is completed, the value of the storage space in the stack corresponding to the variable is not allowed to be changed, otherwise an error will be reported. [When the variable is declared, apply for space from the stack to store the value of the variable]

Disclose a bit. If the const variable is assigned a js object [accurately speaking, it is a reference type of data], the properties of the object are allowed to be changed. Because const only restricts the value in the stack from being changed. When an object is given to a variable, it assigns the address of the object itself to the storage space in the stack. And his own data is stored in the heap. So how to modify the data in the heap has nothing to do with const.

Can the variables declared in different