let and const commands

 

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

In the above code, the variable i is declared by let, and the current i is only valid in this cycle, so the i of each cycle is actually a new variable, so the final output is 6.

1. There is no variable promotion

let doesn't "variably hoist" like var does. Therefore, the variable must be used after the declaration, otherwise an error will be reported

Two temporary dead zones

ES6 clearly stipulates that if there are let and const commands in a block, the variables declared by this block for these commands form a closed scope from the beginning. Anytime these variables are used before they are declared, an error will be reported. This is syntactically called a "temporal dead zone" (TDZ).

if (true) {
  // TDZ start
  tmp = 'abc'; // ReferenceError
  console.log(tmp); // ReferenceError

  let tmp; // TDZ Finish
  console.log(tmp); // undefined

  tmp = 123;
  console.log(tmp); // 123
}

"Temporary dead zone" also means that typeof is no longer a 100% safe operation.

typeof x; // ReferenceError
let x;

Some "dead zones" are hidden and not easy to spot.

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

bar(); // report an error

In the above code, the reason why calling the bar function reports an error (some implementations may not report an error) is because the default value of the parameter x is equal to another parameter y, and at this time, y has not been declared and belongs to the "dead zone". If the default value of y is x, no error will be reported, because x has already been declared.

ES6 stipulates that temporary dead zones and let and const statements do not have variable promotion, mainly to reduce runtime errors and prevent variables from being used before they are declared, resulting in unexpected behavior. Mistakes like this are common in ES5, and now with this provision, it's easy to avoid them.

In short, the essence of the temporary dead zone is that as soon as the current scope is entered, the variable to be used already exists, but cannot be obtained. Only when the line of code that declares the variable appears, can the variable be obtained and used.

3 Repeated declarations are not allowed

// report an error
function () {
  let a = 10;
  var a = 1;
}

// report an error
function () {
  let a = 10;
  let a = 1;
}
function func(arg) {
  let arg; // report an error
}

function func(arg) {
  {
    let arg; // no error
  }
}

Four block scopes

ES5 only has global scope and function scope, and no block-level scope, which brings many unreasonable scenarios.

In the first scenario, inner variables may override outer variables.

var tmp = new Date();

function f() {
  console.log(tmp);
  if (false) {
    var tmp = "hello world";
  }
}

f(); // undefined

In the above code, after the function f is executed, the output result is undefined, because the variable promotion causes the inner tmp variable to overwrite the outer tmp variable.

In the second scenario, the loop variable used for counting is leaked as a global variable.

var s = 'hello';

for (var i = 0; i < s.length; i++) {
  console.log(s[i]);
}

console.log(i); // 5

In the above code, the variable i is only used to control the loop, but after the loop ends, it does not disappear and leaks into a global variable.

The advent of block-level scope actually made the widely used Immediately Executed Anonymous Functions (IIFE s) unnecessary. 

// IIFE spelling
(function () {
  var tmp = ...;
  ...
}());

// block-scoped writing
{
  let tmp = ...;
  ...
}

 

const command

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

A const-declared variable must not change its value, which means that once a const variable is declared, it must be initialized immediately and cannot be left for later assignment.

const foo;
// SyntaxError: Missing initializer in const declaration

The scope of const is the same as that of the let command: it is only valid within the block-level scope in which it is declared.

The constant declared by the const command is also not promoted, and there is also a temporary dead zone, which can only be used after the declared position.

The constant declared by const is also not repeatable declaration like let.

const a = [];
a.push('Hello'); // executable
a.length = 0;    // executable
a = ['Dave'];    // report an error

In the above code, the constant a is an array, and the array itself is writable, but if you assign another array to a, an error will be reported.

If you really want to freeze the object, you should use the Object.freeze method.

const foo = Object.freeze({});

// In regular mode, the following line does not work;
// In strict mode, this line will report an error
foo.prop = 123;

In the above code, the constant foo points to a frozen object, so adding new properties doesn't work, and an error will be reported in strict mode.

In addition to freezing the object itself, the properties of the object should also be frozen. Below is a function that completely freezes an object.

var constantize = (obj) => {
  Object.freeze(obj);
  Object.keys(obj).forEach( (key, value) => {
    if ( typeof obj[key] === 'object' ) {
      constantize( obj[key] );
    }
  });
};

Properties of the global object

Undeclared global variables automatically become properties of the global object window, which is considered to be one of the biggest design flaws of the JavaScript language. This design brings two big problems. First, it is impossible to report an undeclared variable error at compile time, which can only be known at runtime. Second, it is easy for programmers to create global variables unknowingly ( such as typing errors). On the other hand, it is also inappropriate, semantically speaking, for the top-level object of a language to be an object with entity meaning.

 In order to change this, ES6 stipulates that, in order to maintain compatibility, the global variables declared by the var command and the function command are still attributes of the global object; on the other hand, the global variables declared by the let command, const command, and class command are specified. Properties that are not part of the global object. That is, starting with ES6, global variables will gradually be decoupled from properties of the global object.

var a = 1;
// if in Node of REPL environment, which can be written as global.a
// Or in a generic way, written as this.a
window.a // 1

let b = 1;
window.b // undefined

In the above code, the global variable a is declared by the var command, so it is a property of the global object; the global variable b is declared by the let command, so it is not a property of the global object and returns undefined.

Tags: Javascript

Posted by supinum on Tue, 17 May 2022 18:23:39 +0300