This is the 8th day of my participation in Gwen Challenge

ES6 added the let command to declare variables. Its use is similar to var, but the declared variable is only valid within the code block in which the let command resides. Const declares a read-only constant. Once declared, the value of a constant cannot be changed.

Basic use of let

What is printed in the for loop

for (var i = 0, arr1 = []; i <= 3; i++) {
    arr1.push(function () {
        console.log(i)
    });
}
arr1[0] ();/ / 4

for (var i = 0, arr2 = []; i <= 3; i++) {
    arr2.push(
        (function (i) {
            return function () {
                console.log(i);
            }
        })(i)
    );
}
arr2[0] ()/ / 0

let arr3 = []
for (let i = 0; i <= 3; i++) {
    arr3.push(function () {
        console.log(i)
    });
}
arr3[0] ();/ / 0
Copy the code

Scope for

When let is combined with for, the scope is strange. Another special feature of the for loop is that the part that sets the variable of the loop is a parent scope, while the inner part of the loop body is a separate child scope. The following code uses let to print ABC three times. This indicates that the variable I inside the function and the loop variable I are not in the same scope and have separate scopes. The second one using var directly prints NaN.

for (let i = 0; i < 3; i++) {
  let i = 'abc';
  console.log(i);
}
// abc
// abc
// abc

for (var i = 0; i < 3; i++) {
    var i = 'abc';
    console.log(i);// abc
}
console.log(i)// NaN

// abc
// NaN
Copy the code

Variable promotion? No!

A temporary dead zone

Typeof is not safe in dead zones

// Es6 syntax is used. The default mode is strict
function bar(x = y, y = 2) {
    return [x, y];
}

bar(); / / an error

Copy the code

Duplicate declarations are not allowed

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

function func(arg) {{let arg; / / is not an error}}Copy the code

Block-level scope

Why do you need block-level scopes

ES5 has only global and functional scopes, not block-level scopes, which leads to a lot of irrational scenarios.

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

var tmp = new Date(a);function f() {
  console.log(tmp);
  if (false) {
    var tmp = 'hello world';
  }
}

f(); // undefined
Copy the code

The if block uses the TMP variable in the outer layer and the TMP variable in the inner layer. The TMP variable in the inner layer overwrites the TMP variable in the outer layer.

In the second scenario, loop variables used to count are exposed as global variables.

var s = 'hello';

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

console.log(i); / / 5
Copy the code

In the code above, the variable I is used only to control the loop, but when the loop ends, it does not disappear and leaks out as a global variable.

ES6 block-level scope

The emergence of block-level scopes virtually eliminates the need for the widely used immediate-execution function expressions (IIFE).

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

// block level scope
{
  lettmp = ... ; . }Copy the code

Block-level scopes and function declarations

Can functions be declared in block-level scopes? This is a rather confusing question.

ES5 states that functions can only be declared in top-level scopes and function scopes, not block-level scopes.

/ / a
if (true) {
  function f() {}}/ / 2
try {
  function f() {}}catch(e) {
  // ...
}
Copy the code

However, browsers do not comply with this rule and, for compatibility with older code, still support declaring functions in block-level scopes, so both cases actually work without error.

ES6 introduces block-level scopes, explicitly allowing functions to be declared in block-level scopes. ES6 states that a function declaration statement in a block-level scope behaves like a LET and cannot be referenced outside the block-level scope.

function f() { console.log('I am outside! '); }

(function () {
  if (false) {
    // declare the function f again
    function f() { console.log('I am inside! '); } } f(); } ());/ / ES5 environment
function f() { console.log('I am outside! '); }

(function () {
  function f() { console.log('I am inside! '); }
  if (false) { } f(); } ());// ES6 environment of the browser
function f() { console.log('I am outside! '); }

(function () {
  if (false) {
    // declare the function f again
    function f() { console.log('I am inside! '); } } f(); } ());// Uncaught TypeError: f is not a function

// ES6 environment of the browser
function f() { console.log('I am outside! '); }
(function () {
  var f = undefined;
  if (false) {
    function f() { console.log('I am inside! '); } } f(); } ());// Uncaught TypeError: f is not a function
Copy the code

Run it on ES5, and you’ll get “I am Inside!” Because f declared inside if is promoted to the function header, the actual code to run is as follows.

The ES6 is completely different, theoretically getting “I am outside!” . Because functions declared inside the block-level scope are like lets, they have no effect outside the scope. However, if you actually run the above code in an ES6 browser, you will get an error. Why?

It turns out that if you change the processing rules for functions declared in block-level scopes, you can obviously have a big impact on older code. To mitigate the resulting incompatibilities, ES6 provides in Appendix B that browser implementations can behave in their own way.

  • Allows functions to be declared in block-level scopes.
  • Function declarations are similar to var in that they are promoted to the global scope or to the head of the function scope.
  • Function declarations are also promoted to the head of their block-level scope.

Note that the above three rules apply only to browser implementations of ES6. Implementations of other environments do not follow these rules, and block-scoped function declarations are treated as lets.

According to these three rules, in the browser’s ES6 environment, block-level scoped functions behave like variables declared by var.

You should avoid declaring functions in block-level scopes because of the wide variation in behavior caused by the environment. If necessary, write it as a function expression rather than a function declaration statement.

// Function declaration statement
{
  let a = 'secret';
  function f() {
    returna; }}// Function expression
{
  let a = 'secret';
  let f = function () {
    return a;
  };
}
Copy the code

There is another caveat. ES6’s block-level scope allows you to declare rules for functions only if braces are used, and an error is reported if braces are not used.

/ / is not an error
'use strict';
if (true) {
  function f() {}}/ / an error
'use strict';
if (true)
  function f() {}
Copy the code

const

Basic usage

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

const PI = 3.1415;
PI / / 3.1415

PI = 3;
// TypeError: Assignment to constant variable.
Copy the code

The above code shows that changing the value of a constant causes an error.

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 foo;
// SyntaxError: Missing initializer in const declaration
Copy the code

nature

What const actually guarantees is not that the value of the variable is fixed, but that the memory address to which the variable refers is fixed. In other words, const doesn’t really change the value of a constant on the stack. If the value is a primitive data type, const keeps the value constant. If it is a reference type, the stack actually holds the address of the corresponding constant. The address cannot be changed, but the heap contents of the corresponding address can be.

For data of simple types (values, strings, booleans), the value is stored at the memory address to which the variable points, and is therefore equivalent to a constant. But in the case of composite types (mainly objects and arrays), the const pointer is guaranteed to be fixed, and the data structure it points to is mutable. Therefore, declaring an object as a constant must be done with great care.

const foo = {}; // Add an attribute to foo, which succeeds foo.prop = 123; Foo. Prop // 123 // Pointing foo to another object will result in an error foo = {}; // TypeError: "foo" is read-only const a = []; a.push('Hello'); // execute a.length = 0; A = ['Dave']; / / an errorCopy the code

In the code above, the constant foo stores an address that points to an object. Only the address is immutable, that is, you can’t point foo to another address, but the object itself is mutable, so you can still add new attributes to it. The constant A is an array. The array itself is writable, but an error is reported if another array is assigned to A. If you really want to freeze an Object, you should use the object. freeze method. Adding new attributes does not work and an error will be reported in strict mode. In addition to freezing the object itself, properties of the object should also be frozen.

ES6 six ways to declare variables

ES5 has only two methods for declaring variables: the var command and the function command. In addition to the let and const commands, ES6 has two other ways to declare variables, the import command and the class command, as discussed in a later section. So there are six ways to declare variables in ES6.

Properties of the top-level object

The top-level object refers to the Window object in the browser environment and the Global object in Node. In ES5, attributes of top-level objects are equivalent to global variables.

window.a = 1;
a / / 1

a = 2;
window.a / / 2
Copy the code

In the code above, the assignment of attributes to top-level objects is the same thing as the assignment of global variables.

The attributes of top-level objects are linked to global variables, which is considered one of the biggest design failures of the JavaScript language. There are several major problems with this design. First, there is no way to report an undeclared variable error at compile time, which is only known at run time (because global variables can be created by attributes of top-level objects, which are created dynamically). Second, it is easy for programmers to unknowingly create global variables (such as typos). Finally, the properties of the top-level object are read and written everywhere, which makes modular programming very difficult. On the other hand, the window object has an entity meaning, which refers to the browser window object, and the top-level object is an entity meaning object, which is also inappropriate.

In order to change this, ON the one hand, ES6 stipulates that, in order to maintain compatibility, global variables declared by var and function commands are still attributes of top-level objects. On the other hand, global variables declared by let, const, and class are not attributes of the top-level object. That is, starting with ES6, global variables will gradually be decoupled from the properties of top-level objects.

var a = 1;
// If in the REPL environment of Node, it can be written as global.a
// Or, in general, write this.a
window.a / / 1

let b = 1;
window.b // undefined
Copy the code

In the code above, the global variable A is declared by the var command, so it is a property of the top-level object; The global variable B is declared by the let command, so it is not a property of the top-level object and returns undefined.

Global object

The top-level object of ES5 is itself a problem because it is not uniform across implementations.

  • In browsers, the top-level object is window, but Nodes and Web workers don’t have Windows.
  • In browsers and Web workers, self also points to the top-level object, but Node has no self.
  • In Node, the top-level object is global, which is not supported in any other environment.

In order for the same code to be able to fetch the top-level object in any environment, it is now common to use this variable, but there are limitations.

  • In a global context, this returns the top-level object. However, in the Node module and ES6 module, this returns the current module.
  • This inside of a function, if the function is not run as a method on an object, but is simply run as a function, this points to the top-level object. However, in strict mode, this will return undefined.
  • In strict or normal mode, new Function(‘return this’)() always returns a global object. However, if the browser uses CSP (Content Security Policy), methods such as eval and new Function may not work.

In summary, it’s hard to find a way to get to the top-level object in all cases. Here are two methods that can be used reluctantly.

/ / method
(typeof window! = ='undefined'
   ? window
   : (typeof process === 'object' &&
      typeof require= = ='function' &&
      typeof global= = ='object')?global
     : this);

/ / method 2
var getGlobal = function () {
  if (typeofself ! = ='undefined') { return self; }
  if (typeof window! = ='undefined') { return window; }
  if (typeof global! = ='undefined') { return global; }
  throw new Error('unable to locate global object');
};
Copy the code

There is now a proposal to introduce Global as a top-level object at the level of language standards. That is, in all circumstances, global exists and can be retrieved from it.

The above! Last rule, post my blog, welcome to follow

Please pay attention to the official number: Full stack flying Squadron

The resources

Js about closures in for loops?

The above! Last rule, post my blog, welcome to follow

Please pay attention to the official number: Full stack flying Squadron