By Mika

Var, let, and const

Let and const are new features in ECMAScript6. Let is the “standard” that can replace var, so when we discuss the difference between var, let and const, we should first know what is wrong with var, or what is wrong with var.

The characteristics of the var

Variable ascension

Var is a keyword used by Javascript to define variables. This is a simple way to define variables

var a = 0;
Copy the code

But if we look up this a before we define this variable, we don’t actually get an error

console.log(a); // undefined
var a = 0;
console.log(a); / / 0
Copy the code

It prints undefined, but that’s not what we want. We want the variable not to be accessible until it’s initialized. This is a constraint, but it makes your program more subtle and maintainable. And the reason why var can be at var a = 0; Before is accessed because this sentence is actually compiled in the following order:

var a;
console.log(a); // undefined
a = 0;
console.log(a); / / 0
Copy the code

That’s why the second line, a, prints undefined. This is called variable promotion. When using var to initialize a variable, the variable is defined at the beginning of the scope and then assigned (initialized) later. So you can even play like this:

console.log(a); // undefined
a = 0;
console.log(a); / / 0
var a;
Copy the code

This will print successfully, so you can see how var can be a problem for program maintenance, right? When A looked down all the way and didn’t see it, it was still in normal use? !!!!! You need to look at the scope to see if there is any hidden var a; If not, you need to look outside the area.

console.log(a); // undefined
let a = 0;
console.log(a); / / 0
Copy the code
Scope of var

Let’s look at the following code again

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

The variables “I” and “a” that we defined in the for loop block can be accessed outside of the loop, which is obviously not the norm.

So here’s another question that’s often mentioned in interviews

for (var i = 0; i < 5; i++) {
    setTimeout(function () {
        console.log(i); // 5 5 5 5 5 5
    }, 300);
}
for (let j = 0; j < 5; j++) {
    setTimeout(function () {
        console.log(j); // 0 1 2 3 4
    }, 300);
}
Copy the code

Almost identical code, but because of the scope difference between var and let, the results are very different. For the first for loop, I is valid globally. There is no definition of I in the setTimeout function, so the variable I is found globally. After the for loop completes, the anonymous function in the event loop, setTimeout, begins to execute. At this point the global I is actually 5, so it prints out all 5. For the second for loop, the let has the concept of block-level scope, and it’s worth noting that the let declaration at the head of the for loop has a special behavior that indicates that the variable is declared not just once during the loop, but every iteration. Each subsequent iteration initializes the variable with the value at the end of the previous iteration. This makes our j, each execution of which is actually a different variable in the block-level scope, not the final 5. So if you can’t use E6, you can use closures to create a new scope. The closure preserves a reference to the scope where it is declared, forcing I into the scope of the self-executing function so that it cannot be reclaimed. So you get the value of I every time.

for (var i = 0; i < 5; i++) {
    (function (i) {
        setTimeout(function () {
            console.log(i) // 0 1 2 3 4
        }, 300)
    })(i)
}
Copy the code
Var can be defined repeatedly

This makes sense. Var is allowed to be defined twice, and no error is reported.

var a = 0;
console.log(a); / / 0
var a = 1;
console.log(a); / / 1
Copy the code

The editor will ignore the var keyword when it determines that there is an already declared variable of the same name and assign directly, so if a reused declaration has an initial value, it is an assignment statement. If a repeated declaration does not have an initial value, it has no effect on the existing variables. This is legal for JS before ES5, but after ES6, it is considered unscientific to repeat the definition. Let and const are not allowed to repeat a variable with the same name in the scope.

Now let’s talk about let

Temporary dead zone

First, you are absolutely not allowed to use a variable before let defines it

console.log(a); // ReferenceError: a is not defined
let a = 0;
console.log(a); / / 0
Copy the code

Let declarations are not promoted to the top of the current execution context, starting at the block-level scope and going to the initialization location, called the “staging dead zone,” so using a in staging dead zones for A will cause a “Reference” error.

Block-level scope

Unlike var, variables defined in a for loop can be accessed externally. This can lead to some unexpected bugs. Note that the braces {} are block-level scoped, not function scoped.

No redefinition
let a = 0;
console.log(a); / / 0
let a = 1;
console.log(a); // SyntaxError: Identifier 'a' has already been declared
Copy the code
The window object

In HTML, global scope is for the window object. Global scope variables defined by the var keyword belong to the window object, while those defined by let do not. Note that this is in a browser environment; there is no window object for Node.

var a = 0;
console.log(window.a) / / 0
let b = 1;
console.log(window.b) // undefined
Copy the code

const

In fact, const and let are very, very similar. They have all the same properties that let have, except that, first, const is not allowed to “modify” a variable. Second const must be initialized

const a = 0;
a = 1; // TypeError: Assignment to constant variable
Copy the code
const b; // SyntaxError: Missing initializer in const declaration
Copy the code

If you define an object or an array, you can change it, but you can’t assign different data types to it.

const a = {}
a.b = 1;
console.log(a) // { b: 1 }
a = 1 // TypeError: Assignment to constant variable
Copy the code

This article was typeset using MDNICE