The introduction

This article mainly introduces the meaning of var, let, const keywords, and from

  • Scope rule
  • Repeat declaration/repeat assignment
  • Variable promotion (hoisted)
  • Temporary Dead Zones (TDZ)

Var, let, and const are declared in four different ways

var

Before ES6 we defined JavaScript variables with the var keyword. The let and const keywords were added in ES6

var num = 1
Copy the code

Declare a variable in the global scope using var. By default, it is mounted under the top-level object Window (Node is global).

var num = 1
console.log(window.num) / / 1
Copy the code

The scope of a variable declared with VAR is its current execution context, which can be functional or global

var x = 1 // declare under global scope
function foo() {
    var x = 2 // declare in the scope of foo
    console.log(x) / / 2
}
foo()
console.log(x) / / 1
Copy the code

If x is not declared in foo, but is assigned, then x is assigned in the outer scope of foo

var x = 1 // declare under global scope
function foo() {
    x = 2 / / assignment
    console.log(x) / / 2
}
foo()
console.log(x) / / 2
Copy the code

If assigned to an undeclared variable, the variable is implicitly created as a global variable (it becomes a property of the top-level object)

a = 2
console.log(window.a) / / 2

function foo(){
    b = 3
}
foo()
console.log(window.b) / / 3
Copy the code

Var defect 1: All variables that are not declared and assigned directly will be automatically hung under the top-level object, resulting in uncontrollable and chaotic global environment variables

Variable promotion (hoisted)

Variables declared using var may be promoted

console.log(b) // undefined
var b = 3
Copy the code

Note that promotion is only a variable declaration and does not affect the initialization of its value. It can be understood implicitly as:

var b
console.log(b) // undefined
b = 3
Copy the code

Scope rule

The var declaration can be accessed anywhere within the containing function, module, namespace, or global scope. The containing code block has no effect on this, so declaring the same variable more than once does not cause an error:

var x = 1
var x = 2
Copy the code

This scoping rule can cause some errors

function sumArr(arrList) {
    var sum = 0;
    for (var i = 0; i < arrList.length; i++) {
        var arr = arrList[i];
        for (var i = 0; i < arr.length; i++) { sum += arr[i]; }}return sum;
}
Copy the code

It’s easy to see the problem here, because the inner for loop overwrites variable I, because all I’s refer to variables in the same function scope. As experienced developers are well aware, these issues can be missed during code review and cause endless trouble.

Var defect 2: Allows multiple declarations of the same variable without an error, making the code difficult to maintain

Capture variable quirks

var a = [];
for (var i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6] ();/ / 10
Copy the code

I is the global variable, and there is only one global variable I. At the end of the for loop, I =10, so a[6]() is also 10, and I is 10 in all elements of A

Instead, we expect a[6]() to output 6, so we have the following block-level scope

let

Let is written the same way as var, except that it uses block scope

let a = 1
Copy the code

Block-scoped variables are not accessible outside the block or for loop that contains them

{
    let x = 1
}
console.log(x) // Uncaught ReferenceError: x is not defined
Copy the code

So:

var a = [];
for (let i = 0; i < 10; i++) { // Each loop I is a new variable
  a[i] = function () {
    console.log(i);
  };
} // The JavaScript engine internally remembers the value of the previous cycle, and when it initializes the variable I of this cycle, it evaluates on the basis of the previous cycle
a[6] ();/ / 6
Copy the code

At the same time, let solves two defects of VAR:

Variables declared under the global scope using let are also not attributes of the top-level object

let b = 2
window.b // undefined
Copy the code

Then where is it?

var a = 1
let b = 2
debugger
Copy the code

As you can also see from the figure above, global variables declared with lets and const are not in the global object, but in a block-level scope (Script)

Duplicate declarations are not allowed in the same block

let x = 1
let x = 2
// Uncaught SyntaxError: Identifier 'x' has already been declared
Copy the code

It can be declared if it’s in different blocks

{
    let x = 1
    {
        let x = 2}}Copy the code

This behavior of declaring the same variable name in a nested scope is called masking, and it perfectly solves the sumArr problem above:

function sumArr(arrList) {
    let sum = 0;
    for (let i = 0; i < arrList.length; i++) {
        var arr = arrList[i];
        for (let i = 0; i < arr.length; i++) { sum += arr[i]; }}return sum;
}
Copy the code

I’ll get the right answer, because I in the inner loop can mask I in the outer loop

Masking should generally be avoided because we need to write clean code. There are also scenarios where you can use it, and you need to think about it

Temporary Dead Zones (TDZ)

A variable declared by a let cannot be accessed until it is declared

console.log(x) // Uncaught ReferenceError: x is not defined
let x = 1
Copy the code

If you declare let in a block, it will report the following error:

// let
{
    console.log(x) // Uncaught ReferenceError: Cannot access 'x' before initialization
    let x = 2
}
Copy the code

That is, if the error content is uninitialized in the block-level scope, is the let promoted in the block-level scope?

In reactors-VS-TDZ. MD, TC39 member Rick Waldron puts it this way:

In JavaScript, all binding declarations are instantiated when control flow enters the scope in which they appear. Legacy var and function declarations allow access to those bindings before the actual declaration, with a “value” of undefined. That legacy behavior is known as “hoisting”. let and const binding declarations are also instantiated when control flow enters the scope in which they appear, with access prevented until the actual declaration is reached; this is called the Temporal Dead Zone. The TDZ exists to prevent the sort of bugs that legacy hoisting can create.

Translation:

In JavaScript, all binding declarations are instantiated when the control flow enters the scope where they appear. Traditional var and function declarations allow access to those bindings before they are actually declared, and their value is undefined. This legacy behavior is known as variable promotion. Let and const declarations are also instantiated when the control flow enters the scope where they occur, but access is denied until the actual declaration is run. This is called a Temporal Dead Zone. TDZ exists to prevent the kind of errors that traditional ascension can cause.

That is, let/const variables are always “present” in their scope, but cannot be accessed before let/const statements, so they are not called variable promotions, only temporary dead zones

const

Const declares a read-only constant. Once declared, the value of a constant cannot be changed.

const a = 1

a = 2 // Uncaught TypeError: Assignment to constant variable.
Copy the code

Therefore, a variable declared by const may not change its value, which means that a const, once declared, must be initialized immediately and cannot be left for later assignment.

const s // Declare no value assigned
// Uncaught SyntaxError: Missing initializer in const declaration
Copy the code

Note that const does not guarantee that the value of the variable is fixed, but that the memory address to which the variable refers is fixed. For primitive types, the value of the variable is stored at that memory address, where it is always on. For reference types, its internal value can be changed

const num = 1
const user = {
    name: "sisterAn".age: num,
}

user = {
    name: "pingzi".age: num
} // Uncaught TypeError: Assignment to constant variable.

// All of the following are running successfully
user.name = "Hello"
user.name = "Kitty"
user.name = "Cat"
user.age--
Copy the code

Other const is the same as let, for example:

  • Same scope, valid only in the block-level scope of the declaration
  • Constants also do not ascend and also have temporary dead zones

I won’t repeat it here

var vs let vs const

Var, let, and const differ in the following ways:

  • Scope rule
  • Repeat declaration/repeat assignment
  • Variable promotion (hoisted)
  • Temporary Dead Zones (TDZ)

Scope rule

Variables declared by let/const are block-scoped and are only available in their blocks or subblocks. The scope of a variable declared by var can be global or the whole enclosing function

Repeat declaration/repeat assignment

  • varRepeated declarations and repeated assignments are possible
  • letOnly repeated assignments are allowed, but no repeated declarations are allowed
  • constNeither assignment nor declaration can be repeated

Variable promotion (hoisted)

The variable declared by var has variable promotion, that is, it can be accessed before the variable is declared, and its value is undefined

Let and const do not have variable promotion, that is, the variables they declare must be used after declaration, otherwise ReferenceError is reported

Var:

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

Let:

console.log(b) // Uncaught ReferenceError: b is not defined
let b = 2
Copy the code

Const:

console.log(c) // Uncaught ReferenceError: c is not defined
let c = 3
Copy the code

Temporary Dead Zones (TDZ)

Var does not have a temporary dead band. Let and const have a temporary dead band and can only be accessed or used after a variable has been declared

Programming style

ES6 introduced two new commands to declare variables: let and const. Among them, let can completely replace VAR because the semantics are the same and let has no side effects. Therefore, we recommend using let and const instead of var in our development

reference

  • MDN
  • Ruan Yifeng: An Introduction to ECMAScript 6

Three minutes a day