ES6 - Block Scope

Keywords: Javascript Attribute

Previous remarks

In the past, javascript lacked block level Scope , when var is declared Declaration Promotion,Attribute variable Behaviors such as these are confusing.The new syntax for ES6 can help us better control the scope.This article details the new block-level scope binding mechanism, let and const declaration mechanism, and best practices introduced by ES6

 

var declaration

[Variable promotion]

Variable promotion occurs when var declarations, that is, variables can be used before they are declared with a value of undefined

function getValue(condition){
    if(condition){
        var value = 'blue';
        return value;
    }else{
     //The variable value, undefined, is accessible here
return null; }
    //The variable value, undefined, is accessible here }

Without experience with javascript development, you might think that variable value will only be created if condition is true

In practice, however, during the precompilation phase, the javascript engine will modify the above function to look like this

function getValue(condition){
    var value;
    if(condition){
        value = 'blue';
        return value;
    }else{
        return null;
    }
}

The declaration of the variable value is promoted to the top of the function, while the initialization remains in place.If you don't pay attention, you are likely to get an error.For this reason, ES6 introduces a block-level scope to enhance control over the life cycle of variables

[Block level declaration]

Block-level declarations are used to declare variables that are inaccessible outside the scope of a specified block and that exist

1. Inside Function

Within block area between 2, {}

 

let declaration

The let declaration is used the same as the var declaration.Declaring variables with let instead of var limits their scope to the current block of code

function getValue(condition){
    if(condition){
        let value = 'blue';
        return value;
    }else{
         //variable value Does not exist here
        return null;
    }
    //variable value Does not exist here
}

After the variable value is declared by the keyword let, it is no longer promoted to the top of the function.When the execution stream leaves the if block, the value is immediately destroyed.If the condition value is false, the value will never be declared and initialized

[No redeclaration]

Assuming that an identifier already exists in the scope, declaring it with the let keyword will throw an error

var count = 30;
//Throw a grammar error
//Uncaught SyntaxError: Identifier 'count' has already been declared
let count = 40;

 

const declaration

Const is used to declare constants whose values cannot be changed once they are set.Therefore, each constant declared through const must be initialized

const num = 30;
//Throw a grammar error
//Uncaught SyntaxError: Missing initializer in const declaration
const name;

const and let declare the teacher block level identifier, so constants are only valid in the current block of code and are destroyed as soon as they are executed outside the block.Constants are also not promoted to the top of the scope

if(condition){
    const num = 30;    
}
//Not accessible here num

[No redeclaration]

Similar to lets, declaring an existing identifier with const within the same scope can also result in syntax errors, whether the identifier is declared with var or let

var message = 'hello';
let num = 10;

//Both statements throw errors
const message = "goobye";
const num = 30;

[No more assignments]

The biggest difference between const and let declarations is that const declarations can no longer be assigned constants

let num1 = 10;
num1= 20;

const num2 = 10;
//Uncaught TypeError: Assignment to constant variable.
num2 = 20;

[Object properties can be modified]

The const declaration does not allow modification of bindings, but allows modification of values.This also means that once an object is declared with a const, its property values can be modified

const person = {
    name: 'huochai'
};
//You can modify the value of an object property
person.name = 'match';
//Object {name: "match"}
console.log(person);

//Throw a grammar error
//Uncaught TypeError: Assignment to constant variable.
person = {
    name: 'match'
}

 

Temporary Dead Zone

Unlike var, variables declared by let and const are not promoted to the top of the scope, and accessing them before declaration can cause errors.The area from the top of the scope to the area before the variable statement is called the temporal dead zone, or TDZ for short.

if(true){
    //undefined
    console.log(typeof value);
    var value = "blue";
}

if(true){
    //Uncaught ReferenceError: value is not defined
    console.log(typeof value);
    let value = "blue";
}

However, using this variable outside the scope of a let or const declaration will not cause errors

//undefined
console.log(typeof value);
if(true){
    let value = "blue";
}

 

Circular Binding

[var statement]

The var declaration has long made it difficult to create functions in a loop because variables are still accessible outside the loop

var funcs = [];
for(var i = 0; i < 10; i++){
    funcs.push(function(){
        //Output 10 times 10
        console.log(i);
    });
}
funcs.forEach(function(func){
    func();
})

In the code above, the expected result is the output number 0-9, but it outputs 10 times in a series, because each iteration in the loop shares the variable i, the functions created inside the loop keep all references to the same variable, and the variable I at the end of the loop has a value of 10, so each time console.log(i) is called, it outputs 10

[IIFE]

To solve this problem, an immediate call function expression (IIFE) can be used in a loop to force a copy of the counter variable to be generated

var funcs = [];
for(var i = 0; i < 10; i++){
    funcs.push((function(value){
        return function(){
            //0
            //1
            //...
            //9
            console.log(value);
        }
    })(i));
}
funcs.forEach(function(func){
    func();
})

Within the loop, the IIFE expression creates a copy of each accepted variable i and stores it as the variable value, which is the value used by the function created by the corresponding iteration, so each function invoked will get the expected value as from the 0-9 loop

[let]

The let declaration mimics what IIFE did in the example above to simplify the cycle.Each iteration cycle creates a new variable and initializes it with the value of the same variable in the previous iteration

var funcs = [];
for(let i = 0; i < 10; i++){
    funcs.push(function(){
        //0
        //1
        //...
        //9
        console.log(i);
    });
}
funcs.forEach(function(func){
    func();
})

This loop is more concise than the one above, where each time a let declaration creates a new variable I and initializes it to the current value of i, so each function created inside the loop gets a copy of its own I property

The same is true for for-in loops and for-of loops

var funcs = [];
obj = {
    a:true,
    b:true,
    c:true
}
for(let key in obj){
    funcs.push(function(){
        //a
        //b
        //c
        console.log(key);
    })
}
funcs.forEach(function(func){
    func();
})

[const]

For const declarations, the normal for loop cannot be used because it cannot change the value of a variable

var funcs = [];
for(const i = 0; i < 10; i++){
    funcs.push(function(){
            //Uncaught TypeError: Assignment to constant variable.
        console.log(i);
    });
}
funcs.forEach(function(func){
    func();
})

const can be used in for-in loops because each iteration in the for-in loop does not modify existing bindings but creates a new one

var funcs = [];
obj = {
    a:true,
    b:true,
    c:true
}
for(const key in obj){
    funcs.push(function(){
        //a
        //b
        //c
        console.log(key);
    })
}
funcs.forEach(function(func){
    func();
})

 

Attribute variable

Variables declared by var automatically become properties of window objects if they are in global scope.This means that var is likely to inadvertently overwrite an existing global variable

//function RegExp() { [native code] }
console.log(RegExp);
var RegExp = "hello";
console.log(RegExp);//'hello'
console.log(window.RegExp);//'hello'

Variables declared with let or const do not become properties of window objects

let RegExp = "hello";
console.log(RegExp);//'hello'
console.log(window.RegExp);//function RegExp() { [native code] }

Therefore, if you want to define variables under a window object, use the var declaration.If you don't want it, make let or const

 

Best Practices

const is used by default, let is used only if you really need to change the value of a variable

Since the values of most variables should not change after initialization, unexpected changes in variable values are the source of many bug s

Posted by TANK on Tue, 11 Jun 2019 11:14:16 -0700