Block-level scope

Concept: A variable declared by let and const has block-level scope. The variable must be declared inside a function or inside a code block (enclosed by a pair of curly braces)

Advantages: Block-level scope resolves naming conflicts caused by too many global variables and functions

2. Var variable promotion mechanism

2-1 variable promotion

What is variable promotion?

The way a JavaScript engine works is it preparses the code, takes all the variable declarations and function declarations, and then runs them line by line, so that all the variable declarations and function declarations are promoted to the top of the code, and that’s called variable promotion

Var variable promotion

Variables declared by the var keyword are treated as if they are declared at the top of the function (or at the top of the global scope if the declaration is not in any function), regardless of where they are actually declared.

function fn(){
  var a = 1
}
console.log(a) / / an error----------------- splitter ------------------ {var b = 1;
}
console.log(b); / / 1

/ / equivalent to the
var b
{
  b = 1; } ----------------- split line ------------------if(true) {var c = 1;
}
console.log(c); / / 1

/ / equivalent to the
var c
if(true){
  c = 1;
}
Copy the code

2-2 Priority of variable and function declarations

Conclusion: Function declarations take precedence over variable declarations, and eventually the latter is overridden by the former, but assignments can be overridden

Reason: Each time a function is executed, a new private scope (function scope) is formed and the following three steps are performed

  1. If the parameter is tangible, the parameter is assigned first

  2. For private scope preinterpretation, function declarations take precedence over variable declarations, which are eventually overwritten by the former, but can be reassigned

  3. Code in private scopes executes from top to bottom

var a
function a(){}
console.log(a) // [Function a]

function a(){}
var a
console.log(a)// [Function a]

// When a variable is declared without assignment or initialization, the function declaration takes precedence over the variable-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - line -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -var a = 1
function a(){}
console.log(a)	 / / 1
console.log(a()) / / an error

function a(){}
var a = 1
console.log(a)   / / 1
console.log(a()) / / an errorIs equivalent tofunction a(){}
var a
a = 1
console.log(a)   / / 1
console.log(a()) / / an error
Copy the code

2-2 Function expressions and function declarations

Function declaration: A standard function declaration consisting of the keyword function, function name, parameter, and code block.

Function expression: The function has no name and is assigned to a variable on the right side of the assignment statement. When a key function is used in this way in a statement (such as an assignment statement), function expressions are created.

function test() {
    foo(); Uncaught TypeError "foo is not a function"
    bar(); // "this will run!"
    var foo = function() {
        alert("this won't run!");
    };
    function bar() {
        alert("this will run!");
    }
}
test();
Copy the code

Var foo = function(){} var foo = function(){} var foo = function(){}

Let block-level scope

  • Both let and var are used to define variables. Variables declared using let do not have the same variable promotion as var, and let variables are only valid in the current block-level scope
  • It is forbidden to declare the same variable repeatedly in the same scope
// there is no variable promotion, only in the current block-level scope
function person(status) {
    if (status) {
        let value = "Frogman" 
    } else {
        console.log(value) / / an error
    }
    console.log(value) / / an error
}
person(false)

// 2. An error occurs when a variable with the same name is declared in the same scope
var value = "Frogman"
let value = "Frogman" / / an error

// Let's look at the different scopes

var value = "Frogman" // Global scope
if(true) {
	let value = "Frogman" // It is declared in the code block and has no effect
}
Copy the code

4. Const constants

  • A const declaration is a constant. Like a let, it is block-scoped. A constant cannot be modified once defined, and must be initialized otherwise an error will be reported
  • What const actually guarantees is not that the value of the variable cannot be changed, but that the address to which the variable points cannot be changed, i.e. the this pointer cannot be changed. When the property of an object declared by const is modified, the address of the object (a pointer to the object) is not modified, so an object declared by const can be modified

The variable names and values of basic data types are stored in stack memory

The value of the reference data type is a pointer held in stack memory to an object in heap memory. Const only declares that the stack contents remain the same.

Temporary dead zone

As long as the let command exists in the block-level scope, the variables it declares are “binding” to the region, no longer subject to external influence

var tmp = 123;

if (true) {
   tmp = 'abc'; // ReferenceError
   let tmp;
}
Copy the code

In the above code, the global variable TMP exists, but in the block-level scope, let also declared a local variable TMP, which caused the latter to bind to the block-level scope. Therefore, before the let declaration variable TMP, the assignment of TMP will report an error. The TMP variable is in the “dead zone” until it is declared by the let command.

ES6 explicitly states that if there are let and const commands in a block, the variables declared by the block to those commands form a closed scope from the start. Any time these variables are used before declaration, an error is reported. In short, the variable is not available within the code block until it is declared using the let command. This is grammatically known as a “temporal dead zone” (TDZ).

A “temporary dead zone” also means that Typeof is no longer a 100 percent secure operation.

typeof x; // ReferenceError
let x;
// The variable x is declared with the let command, so it belongs to the "dead zone" of x until it is declared. Therefore, the Typeof runtime throws a ReferenceError

typeof y // "undefined"
// y is a nonexistent variable name, returns "undefined". So, before let, typeof operators are 100 percent safe and never report errors. That's no longer true. This is designed to encourage good programming practice. Variables must be used after declaration, otherwise an error will be reported.
Copy the code

A temporary dead zone that is not easy to see

function bar(x = y, y = 2) {
  return [x, y];
}

bar(); / / an error
Copy the code

Call to bar fails because the default value of parameter x is equal to another parameter y, which has not been declared yet. If y defaults to x, no error is reported because x is already declared.