ES6 quick start

ECMAScript overview

JS history

  • JavaScript was born in 1995. NetScape releases NetScape Navigator 2 browser and provides a free development tool LiveScript. The main purpose of the design is to handle some input verification operations previously undertaken by the server-side language. In the age when people generally use telephone dialing to surf the Internet, it is absolutely not easy to complete some basic verification tasks on the client. Because Java is popular, it is renamed JavaScript. This is JavaScript version 1.0.

  • Because JavaScript is very popular, netspace navigator 3 browser has released JavaScript version 1.1. Soon IE3 also added the function of script programming. In order to avoid disputes, it was named JScript.

  • In 1997, ECMA formulated the scripting language standard ECMA-262 based on JavaScript 1.1 and named it ECMAScript. Browser vendors use ECMAScript as the standard for their JavaScript implementations.

    Java is a trademark of Sun company. According to the license agreement, only Netscape company can legally use the name JavaScript, and JavaScript itself has been registered as a trademark by Netscape company. The second is to reflect that the language is formulated by ECMA, not Netscape, which is conducive to ensuring the openness and neutrality of the language.

ECMAScript

In 1997, ECMA issued the first edition of standard document No. 262 (ECMA-262), which stipulated the implementation standard of scripting language and named this standard ECMAScript, which is ES1.0. ECMAScript is the standard of JavaScript language, and JavaScript is an implementation of ECMAScript. It is interchangeable in some contexts.

ECMAScript version

  • ECMAScriysxbzx pt2.0 was released in June 1998
  • In December 1999, ECMAScript version 3.0 was released and became a general standard for JavaScript, which was widely supported
  • In October 2007, ECMAScript version 4.0 draft was released, and version 3.0 was greatly upgraded. Because the goal of version 4.0 is too radical, all parties have serious differences on whether to pass this standard. In July 2008, ECMA suspended the development of ECMAScript 4.0 and released a small part involving the improvement of existing functions as ECMAScript 3.1. Soon, ECMAScript 3.1 was renamed ECMAScript 5
  • ECMAScrip5.0 was officially released in December 2009
  • ECMAScript version 5.1 was released in June 2011
  • In December 2013, ECMAScrip6 draft was released
  • In June 2015, ECMAScript6 was officially released and renamed ECMAScript2015. Mozilla launched JavaScript 2.0 based on this standard
  • Since then, JavaScript has been named after the year, and the new version will be released in the form of "ECMAScript + year". At present, the latest official version is ECMAScript 2019, which was officially released in July 2019

ES6 is not only a historical term, but also a general reference. It means the next generation standard of JavaScript after version 5.1, covering ES2015, ES2016, ES2017, etc. ES2015 is the official name, especially the language standard of the official version released that year

Document address

https://es6.ruanyifeng.com/#docs/intro

Keyword extension (important)

let and block level scopes

Function scope

In ES5, the scope of JS is divided into global scope and local scope. It is usually distinguished by functions. The interior of a function belongs to a local scope.

//Before ES6, only functions formed local scopes
//Case 1
{ var a = 10; }
console.log(a);

//Case 2
console.log(a);
if (true) {
    var a = 10;
}
console.log(a);

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

  • Inner variables may override outer variables.

    var b = 1;
    fn1();
    function fn1() {
        console.log(b);//undefined
        if (true) {
            var b = 2;
        }
    }
    
  • The loop variable used to count is leaked as a global variable.

    //The variable i is declared by the var command and is valid in the global scope, so there is only one variable i in the global scope. With each cycle, the value of variable i changes
    for (var i = 0; i < 5; i++) {
        setTimeout(function () {
            console.log(i);//5 5 5 5 5
        })
    }
    

Block level scope

  • The concept of block level scope is added in ES6. The area expanded with {} is called block level scope
  • let keyword declares variables, which actually adds a block level scope to JavaScript.
  • The block scope consists of {}, and {} in the if statement and for statement also belongs to the block scope.
  • Variables declared with let in the block will only be valid in the current block.
//Globally declare a variable b
let b = 1;
fn1();
function fn1() {
    //The current action has no b, and the global b is found along the action
    console.log(b);
    if (true) {
        //Effective only in the current action
        let b = 2;
    }
}

let keyword

ES6 adds the let command to declare variables. Its usage is similar to var, but the declared variables are only valid in the code block where the let command is located, that is, the block level scope is added.

  • Use block level scope (variables defined by let belong to block level scope) to prevent global variable pollution

    {
        let b = 20;
    }
    console.log(b);//Uncaught ReferenceError: b is not defined
    
    
  • Block level scopes can be nested arbitrarily

    //The outer scope cannot read the variables of the inner scope
    {
        {
            let a = 1;
            {
               console.log(a); //1
            }
        }
        console.log(a);//Uncaught ReferenceError: a is not defined
    }
    
  • The let command is suitable for the counter of the for loop

    //The counter i is only valid in the for loop. If it is referenced outside the loop, an error will be reported
    for (let i = 0; i < 4; i++) {
        console.log(i);
    }
    console.log(i);
    
  • The variable i is declared by let. The current i is only valid in this cycle, so the i of each cycle is actually a new variable

    You may ask, if the variable i of each cycle is redeclared, how does it know the value of the previous cycle and calculate the value of this cycle? This is because the JavaScript engine will remember the value of the previous cycle. When initializing the variable i of this cycle, it will calculate based on the previous cycle

    for (let i = 0; i < 5; i++) {
        setTimeout(function () {
            console.log(i);//0 1 2 3 4
        })
    }
    
  • Another special feature of the for loop is that the part that sets the loop variable is a parent scope, and the interior of the loop body is a separate child scope

    for (let i = 0; i < 4; i++) {
        console.log(i);//a
    }
    console.log(i);//report errors
    
  • practice

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

let keyword features

  1. No promotion declared

    //ES6 clearly stipulates that if there are let and const commands in the block, the variables declared by the block for these commands form a closed scope from the beginning. If these variables are used before declaration, an error will be reported.)
    // This design is to let everyone develop good programming habits. Variables must be used after declaration, otherwise they will report an error
    let c = 1;
    {
        console.log(c);//Uncaught referenceerror: cannot access' C 'before initialization
        let c = 2;
    }
    
  2. Duplicate declarations are not allowed

    // let is not allowed to declare the same variable repeatedly within the same scope
    // report errors
    function func() {
        let a = 10;
        var a = 1;
    }
    
    // report errors
    function func() {
        let a = 10;
        let a = 1;
    }
    
  3. The emergence of block level scope actually makes the widely used anonymous immediate execution function expression (anonymous IIFE) unnecessary

    // IIFE writing method
    (function () {
        var tmp = "...;"
    }());
    
    // Block level scope writing
    {
        let tmp = "...;"
    }
    

const keyword

Constant: data that will not change. Sometimes some data cannot be modified, so constants need to be defined.

  • const declares a read-only constant. Defines that constants can be written in uppercase.

    const PI = "3.1415926";
    console.log(PI)
    
  • const declared constants must not change values

    const PI = "3.1415926";
    PI = 22;//Assignment to constant variable
    
  • If the const declared constant is an object, you can modify the content of the object

    // const can only ensure that the pointer is fixed (that is, it always points to another fixed address). As for whether the data structure it points to is variable, it can not be controlled at all
    //However, the reference of an object cannot be modified. For example, if you replace this object with an object, the reference will be modified
    const PATH = {};
    PATH.name = "lily";
    console.log(PATH);//{name:"lily"}
    PATH = {}//Assignment to constant variableCopy to clipboardErrorCopied
    
  • Once const is declared, it must be initialized immediately and cannot be assigned later

    const time;//SyntaxError: Missing initializer in const declarationCopy to clipboardErrorCopied
    
  • const is only valid within the block level scope where the declaration is located

    {
        const PI = 3.14;
    }
    console.log(PI)//Referenceerror PI is not defined
    
  • Constants declared by const command are also not promoted

    console.log(c);//Cannot access 'c' before initialization
    const c = "hello"
    
  • const is a constant declared, and like let, it cannot be declared repeatedly

    const PI = "3.14";
    const PI = "3.14";//Syntax error: identifier 'Pi' has already been declared
    
  • The global variables declared by the let command, const command and class command do not belong to the properties of the top-level object. In other words, starting from ES6, global variables will be gradually decoupled from the properties of the top-level object.

    var a = 1;
    console.log(window.a);//1
    let a = 2;
    console.log(window.a)//undefined
    

Function declaration for block level scope

Function declarations are generally used in two ways: function declarations and function expressions.

//Function declaration and the difference between the two declarations
f1()//have access to
f2();//f2 is not a function

function f1() {}
var f2 = function () {

}

Can a function be declared in a block level scope? This is a rather confusing question.

  • ES5 stipulates that functions can only be declared in the top-level scope and function scope.
  • ES6 introduces block level scope, which explicitly allows functions to be declared in block level scope. ES6 stipulates that in the block level scope, the behavior of the function declaration statement is similar to that of the let and cannot be referenced outside the block level scope.
  • ES6 stipulates in Appendix B that the implementation of the browser can not comply with the above provisions and has its own behavior
  • Considering that the behavior caused by the environment is too different, you should avoid declaring functions within the block level scope. If necessary, it should also be written as a function expression rather than a function declaration statement.
//Try to avoid the following wording
fn1();
if (true) {
    function fn1() {
        alert(1);
    }
}
fn1();

//If you really want to declare a block level scoped function, use a function expression
if (true) {
    let fn1 = function () {
        alert(1);
    }
}

Variable deconstruction assignment (important)

What is deconstruction assignment of variables

ES6 allows you to extract values from arrays and objects and assign values to variables according to a certain pattern, which is called deconstructing.

The essence of deconstruction assignment is assignment. Dissolving and reconstructing the structure and then assignment is actually a pattern matching. The key is to master the one-to-one correspondence.

The function of deconstruction assignment is to facilitate assignment.

//1. Please assign the values in array arr1 to variables a b c d respectively
//Method of ES5
/* let arr1 = [1, 2, 3, 4];
        let a = arr1[0];
        let b = arr1[1];
        let c = arr1[2];
        let d = arr1[3];
        console.log(a, b, c, d) */

//Deconstruction assignment method
let [a, b, c, d] = [1, 2, 3, 4];
console.log(a, b, c, d)

Deconstruction assignment of array

  • Array deconstruction assignment can extract values from the array and assign values to variables according to their corresponding positions

    let arr = [1, 2]
    let [a, b] = arr;
    console.log(a, b)
    
  • Deconstruction failed, return undefined

    let [c, d] = [1];
    console.log(d);//undefined
    
  • Incomplete deconstruction can also succeed

    let [a] = [10, 20];
    console.log(a);
    
  • You can assign values to deconstruction and set default values

    let [e = 2, f = 20] = [10];
    console.log(e, f)//10 20
    
  • You can use the rest parameter (when there are more values than variables)

    let [g, h, ...rest] = [10, 11, 23, 22, 12, 3, 4, 5, 3];
    console.log(g, h, rest)//10,11,[23, 22, 12, 3, 4, 5, 3]
    
  • Multidimensional arrays can also be assigned as long as the deconstruction relationship is one-to-one corresponding

    let [a, [b, c, d], e] = [1, [2, 3, 4], 5]
    console.log(a, b, c, d, e);
    
  • practice

    // Exercise 1: swap two variables
    let a = 1;
    let b = 2;
    [b, a] = [a, b];//[1,2]
    console.log(a, b)
    
    //Exercise 2
    let [foo = hoo, hoo = 2] = [];
    console.log(foo, hoo)
    

Deconstruction assignment of object

  • Deconstruction can be used not only for arrays, but also for objects

  • There is an important difference between the deconstruction of objects and arrays. The elements of the array are arranged in order, and the value of the variable is determined by its position; The attributes of the object have no order, and the variable must have the same name as the attribute in order to get the correct value

  • The correspondence is based on the key without considering the order

    //Object deconstruction assignment (corresponding relationship is based on key)
    let { foo, hoo } = { foo: "hello", hoo: "word" };//key can be abbreviated as value
    console.log(foo, hoo);
    
    //The origin of {foo,hoo} above
    //In fact, if the key and value of the object are the same, they can be abbreviated
    let a = 1, b = 2;
    console.log({ a: a, b: b })
    console.log({ a, b })
    
    //Find the corresponding relationship between foo and assign 1 to c
    let { foo: c, hoo: d } = { foo: 1, hoo: 2 };
    console.log(foo, hoo);//report errors
    console.log(c, d);//1,2
    
  • Object deconstruction assignment can set default values

    let { x, y = 10 } = { x: 1 };
    console.log(x, y)
    
  • Object and array deconstructions can be nested

    let obj = { a: 1, b: [2, 3, 4] }
    let { a, b: [b1, b2, b3] } = obj;
    console.log(a, b1, b2, b3)
    
  • practice

    //Exercise 1: what if you want to get the first and last values of the array (using deconstruction assignment)
    let arr = [1, 2, 3];
    // Because arrays are special objects in nature, they can be deconstructed
    let { 0: first, [arr.length - 1]: last } = arr;
    
    //Exercise 2: get log method
    let { log } = console;
    log(1);
    

Application of deconstruction assignment

  • Get multiple return values of function

    //1. Receive multiple return values of the function
    function fn(){
        return [1,2,3,4];
    }
    let [a,b,c,d] = fn();
    console.log(a,b,c,d);
    
    function fn() {
        return { foo: "hello", hoo: "word" };
    }
    let { foo } = fn();
    console.log(foo);
    
  • Function parameters

    //2. Function parameters
    function fn1([x,y,z]) {
        console.log(x, y, z);
    }
    fn1([1, 2, 3]);
    
    function fn2({ x, y, z }) {
        console.log(x, y, z);
    }
    fn2({ y: 2, x: 1, z: 3 });
    
  • json data extraction

    //3.json data extraction
    let json = {
        name: "lily",
        sex: "nv",
        age: 18
    }
    let { name, age, sex } = json;
    console.log(name, age, sex)
    

String extension

Template string (important)

  • In the traditional JavaScript language, the output template usually needs to splice strings

    // Original method to make template
    let data = {
        message: {
            title: "The weather is really good today",
            todo: "Play billiards",
            time: "Time 2020.3.25"
        }
    }
    let oOuter = document.getElementById("outer");
    let str = '<div class="box"><h2> ' + data.message.title + '</h2><p>' + data.message.todo + '</p><p>' + data.message.time + '</p></div> ';
    oOuter.innerHTML = str; 
    
  • The template string is an enhanced version of the string, which is identified by backquotes (`). You can nest variables, wrap lines, and contain single and double quotes.

  • It can be used as a normal string or to define a multiline string. Variables are embedded in the template string, and the variable name needs to be written in ${}.

  • Arbitrary JavaScript expressions can be placed inside braces, which can perform operations and reference object properties.

    let data = {
        message: {
            title: "The weather is really good today",
            todo: "Play billiards",
            time: "Time 2020.3.25",
            isLike: false
        }
    }
    let oOuter = document.getElementById("outer");
    let str = `
        <div class="box">
        <h2>${data.message.title}</h2>
        <p>${data.message.todo}</p>
        <p>${data.message.time}</p>
        <p>${data.message.isLike ? "I like you!" : "I don't like you"}</p >
        </div>
    `;
    // oOuter.appendChild(str);//Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.
    oOuter.innerHTML = str;//It needs to be set into the element with innerHTML
    
  • Functions can also be called in the template string.

    function fn(){
        return "hello";
    }
    let str = `${fn()} world`;
    console.log(str);//hello world
    

Method of adding string

  • Go to space

    • trim(): delete the blank characters at both ends of the string
    • trimStart() removes the space in the header
    • trimEnd() removes trailing spaces
    //String is a basic type value. General methods can only return new values, not change the string
    let message = "      hello    world      ";
    log(message);
    
    log(message.trim());
    log(message.trimStart());
    log(message.trimEnd());
    
  • judge

    • startsWith(); Determine whether the beginning contains a string
    • endsWith(); Determine whether the end contains a string
    • includes determines whether a string contains a string
    //String is a basic type value. General methods can only return new values, not change the string
    let message = "hello    world";
    log(message);
    
    log(message.startsWith("hello"));//true
    log(message.endsWith("world"));true
    log(message.endsWith("ld"));//true
    log(message.includes("ld"));//true
    log(message.includes("or"));//true
    log(message.includes("How do you do"));//false
    
  • repeat repeats the current string a specified number of times

    let message = "Hello, Haijing s ah";
    log(message.repeat(10));
    
  • Supplementary character

    • padStart() when the string is less than a certain length, any character is added in the front
    • padEnd(), / / when the string is less than a certain length, any character will be added after it
    let message = "This is the password";
    log(message.padStart(8, '#'))
    log(message.padEnd(8, '#'))
    log(message.padStart(8, '#*2222'))
    

Array extension

Extension operator

What is an extension operator

The spread operator is three dots (...). It is like the inverse operation of rest parameters. It converts an array into a comma separated parameter sequence. At present, it can also be used to expand the array.

let arr = [1, 2, 3];
console.log(...arr);

console.log([1,2,...[3,4,5],6]);//[1,2,3,4,5,6]

This operator is often used for function calls.

//2. Grasp the one-to-one correspondence
function fn(x, y, z) {
    console.log(x, y, z)
}
fn(...arr);

Other applications

  • Copy array
  • Merge array
  • Destructuring assignment
  • Convert string to array
// 1. Copy array: (direct copy in ES5 will generate reference relationship) (ES5 can use concat method to copy array)
let arr2 = [1, 2, 3];
let arr3 = [...arr2];
arr3.push(4);
console.log(arr2, arr3);

//2. Merge arrays
let arr4 = [...arr2, ...arr3];
console.log(arr4);

//3. Deconstruction replication
//Generate an array (in this case, the extension operator must be in the last)
let [a, b, ...newarr] = [1, 2, 3, 4, 5, 5, 6, 8, 9];
console.log(newarr);

//4. String to array
let arr5 = [..."hello"];
console.log(arr5);

New method of array

New method of Array object

Array.from (Practical)

Array.from converts a pseudo array into an array (you can use the array method)

let oLis = document.getElementsByTagName("li");//Pseudo array
for (let i in oLis) {
    console.log(i)//something the matter
    oLis[i].style.color = "red";
}

//Pseudo arrays are not allowed to use arrays
oLis.forEach(function (item, index) {
    console.log(item, index)
});//oLis.forEach is not a function

//3. Use Array.from
// console.log(Array.from(oLis));
// for (let i in Array.from(oLis)) {
//     oLis[i].style.color = "red";
// }

Array.of

Convert a set of numbers into an Array to make up for the deficiency of Array

let arr1 = Array.of(1, 2, 3, 4);
console.log(arr1);
let arr2 = Array.of(1);
console.log(arr2);

New method on Array prototype

Copywithin (understand)

The copyWithin() method of the array instance copies the members at the specified location to other locations within the current array (overwriting the original members), and then returns the current array. That is, using this method will modify the current array

It accepts three parameters.

  • target (required): replace data from this location. If it is negative, it indicates the reciprocal.
  • Start (optional): start reading data from this location. The default value is 0. If it is negative, it means to calculate from the end.
  • End (optional): stop reading data before reaching this position. By default, it is equal to the length of the array. If it is negative, it means to calculate from the end.
{
    let arr = [1, 2, 3, 4, 5, 6, 7, 8];
    arr.copyWithin(0, 4, 6);
    console.log(arr);//[5, 6, 3, 4, 5, 6, 7, 8]
}
{
    let arr = [1, 2, 3, 4, 5, 6, 7, 8];
    arr.copyWithin(0, 3);
    console.log(arr);// [4, 5, 6, 7, 8, 6, 7, 8]
}

Fill (understand)

Populates the array with fixed values

The fill method is very convenient for the initialization of empty arrays. The existing elements in the array will be erased.

The fill method can also accept the second and third parameters to specify the start and end positions of the fill.

let arr2 = [1, 2, 3, 4, 5, 6, 7, 8];
arr2.fill("a");
console.log(arr2);

['a', 'b', 'c'].fill(7, 1, 2)
// ['a', 7, 'c']

entries(), keys() and values()

ES6 provides three new methods -- entries (), keys (), and values () -- for traversing arrays. They all return an ergodic object, which can be traversed by the for...of loop. The only difference is that keys() is the traversal of key names, values() is the traversal of key values, and entries() is the traversal of key value pairs.

//3.entries,keys,values cooperate with for to deconstruct the traversal array
//keys is the subscript of all arrays
let arr3 = ["a", "b", "c", "d", "e"];
console.log(arr3.keys());//Array Iterator
for (index of arr3.keys()) {
    console.log(index);
}
//Values the values of all arrays
for (item of arr3.values()) {
    console.log(item);
}
//values
for (item of arr3.entries()) {
    console.log(item);
}

find() and findindex() (common)

The find method of the array instance is used to find the first qualified array member. Its parameter is a callback function. All array members execute the callback function in turn until the first member whose return value is true is found, and then the member is returned. If there are no qualified members, undefined is returned

let arr4 = ["a", "b", "c", "d", "e"];
let result = arr4.find(function (item, index, arr) {
    console.log(item, index, arr)
    return typeof item == "string"
})
console.log(result);


let arr4 = [{name:"xiaowang1"},{name:"xiaowang2"},{name:"xiaowang3"}];
let result = arr4.findIndex(function (item, index, arr) {
    return typeof item.name == "xiaowang2"
})
console.log(result);

Includes () (Practical)

The includes method returns a Boolean value indicating whether an array contains a given value, similar to the includes method of a string

let arr6 = [1, 2, 3, ["a"]];
console.log(arr6.includes(1));//true
console.log(arr6.includes(["a"]));//false

flat()

  • Array members are sometimes arrays. Array.prototype.flat() is used to "flatten" nested arrays into one-dimensional arrays. This method returns a new array without affecting the original data.
  • By default, flat() will "flatten" only one layer. If you want to "flatten" multi-layer nested arrays, you can write the parameters of the flat() method as an integer to represent the number of layers you want to flatten, which is 1 by default
  • If you want to convert to a one-dimensional array no matter how many layers of nesting, you can use the Infinity keyword as a parameter
{
    //Two dimensional array
    let arr = [1, 2, [3, 4]];
    console.log(arr.flat())
}
{
    //You can pass in parameters if you want to flatten a multidimensional array
    let arr = [1, 2, [3, [5, 6, 7]]];
    console.log(arr.flat(2))
}
{
    //If you don't know how many layers your array has, you can pass infinity to represent infinity
    let arr = [1, 2, [3, [5, 6, 7]]];
    console.log(arr.flat(Infinity))
}

Extension of function

Function parameter defaults (important)

ES5 default parameters

Before ES6, you cannot directly specify default values for function parameters. You can only use flexible methods.

function fn1(a, b) {
    // b = b || "world";
    if (typeof b === "undefined") {
        b = "world";
    }
    console.log(a, b);
}
fn1("hello", "");
fn1("hello");
fn1("hello", "world");

ES6 default parameters

ES6 allows you to set default values for function parameters, that is, write them directly after the parameter definition.

function fn2(a, b = "world") {
    console.log(a, b);
}
fn2("hello", "");
fn2("hello");

rest parameters (remaining parameters) (important)

  • ES6 introduces the rest parameter (in the form of... Variable name) to obtain the redundant parameters of the function, so there is no need to use the arguments object. The variable matched with rest parameter is an array, which puts redundant parameters into the array.
  • When mixed with ordinary parameters, it needs to be placed at the end of the parameters
  • The length attribute of the function, excluding the rest parameter
function fn3(...arg) {
    console.log(arg);
}
fn3(1, 2, 3, 4, 5)

//When mixed with ordinary parameters, it needs to be placed at the end of the parameters
function fn4(a, b, ...arg) {
    console.log(a, b, arg);
}
fn4(1, 2, 3, 4, 5)

Arrow function (important)

What is an arrow function

ES6 allows functions to be defined using "arrows" (= >)

Writing method of arrow function

Arrow functions are divided into the following cases

  • If there is only one parameter, the parentheses can be ignored. When there are no parameters or multiple parameters, the parentheses of the parameters cannot be omitted
  • When the function body is a sentence, you can ignore the curly braces and automatically return this line of code
  • When the function body is not a sentence, you must write {}
//1. When there is only one parameter and the function body is a sentence (return can be omitted if it is a return value)
// let f1 = function (n) {
//     return n + 1;
// }

let f1 = n => n + 1;
console.log(f1(2))

let arr = [1, 2, 3, "a", 5, 6, 7];
let result = arr.find(item => typeof item === "string");
console.log(result);


//2. When there are no parameters or multiple parameters, the parentheses of the parameters cannot be omitted
let f2 = (a, b) => a + b;
console.log(f2(1, 2));

let f3 = () => console.log("hello");
f3();

//3. When the function body is not a sentence
let f4 = (a, b) => {
    console.log(a);
    console.log(b);
    console.log(a + b);
    return "ok~"
}
console.log(f4(1, 2))

Precautions for arrow function

  • The this arrow function does not have its own this. The this inside the arrow function is not the object pointed to when calling, but the object pointed to when defining

    document.onclick = function () {
           console.log(this)//this of a normal function points to the calling object
    }
    
    document.onclick = () => {
         //When defining this arrow function, it is defined in the window environment, so it points to the window
         console.log(this);
    }
    
    document.onclick = function () {
          console.log(this);
          let f = () => {
              console.log(this);
          }
          f();
    }
    
    document.onclick = () => {
          console.log(this);
          let f = () => {
              console.log(this);
          }
          f();
    }
    
  • Arrow functions cannot be used in constructors, that is, they cannot be called with the new keyword

    let F2 = () => { };
    new F2();//F2 is not a constructor
    
  • The arrow function has no arguments object

    let f3 = () => {
          console.log(arguments);//arguments is not defined
    }
    f3(1, 2, 3, 4, 5)
    
  • The arrow function cannot use the yield command, which means it cannot be used as a generator function (which will be described later)

Extension of Math (understand)

Exponential operator

  • In Math, pow's method is provided to calculate the n-th power of a value
  • es2016 proposes a new method to find the n-th power of a value, that is, the * * operator
//Finding the n-th power of a number is a great demand
console.log(Math.pow(3, 3));
console.log(Math.pow(30, 7));


//es2016 proposes a new method to find the n-th power of a value, that is, the * * operator
console.log(3 ** 3);
console.log(30 ** 10);

//The calculation order is calculated first, and then on the right
console.log(3 ** 3 ** 3);

Binary notation

  • Writing binary numbers
  • ES6 represents octal method
//Writing binary numbers
let n1 =  0b00001111;
console.log(n1);//15

//Writing octal
// let n2 = 017;// Error reporting in strict mode
// console.log(n2)

// ES6 represents octal method
let n3 = 0o17; //No error will be reported in strict mode
console.log(n3)

New method of Math

  • The Math.trunc() method removes the decimal part of the number and retains only the integer part
  • Math.sign() determines whether a number is positive or negative, 0 or NaN
  • Math.sqrt() square root
  • Math.cbrt() cube root
  • Math.hypot() finds the square root of the sum of squares of all parameters
const { log } = console;
/*
   Math.trunc()Remove decimal parts
*/
log(Math.floor(1.33));//1
log(Math.ceil(1.33));//2
log(Math.trunc(1.33));//1

log(Math.floor(-1.33));//-2
log(Math.ceil(-1.33));//-1
log(Math.trunc(-1.33));//-1

/*
   Math.sign() Judge whether a number is positive or negative, 0 or NaN
   If it is a positive number, it returns 1. If it is a negative number, it returns - 1. 0. 0. NaN. NaN
*/
log(Math.sign(2.3));//1
log(Math.sign(-1.3));//-1
log(Math.sign(0));//0
log(Math.sign(NaN));//NaN
log(Math.sign(Infinity));//1

/*
    Math.sqrt()square root
    Math.cbrt()Cube root
*/
log(Math.cbrt(27));

/*
   Math.hypot() Find the square root of the sum of squares of all parameters
*/
log(Math.hypot(4, 9, 16))//Math.sqrt(4*4 + 9*9 + 16*16)
//Pythagorean theorem: the 2nd power of a + the 2nd power of b = the 2nd power of c
// It is known that the lengths of the two right sides of a right triangle are 3 and 4. Find the length of the hypotenuse
log(Math.hypot(3, 4))//5

Number extension

  • Number. Isfinish (I): judge whether it is a finite number
  • Number.isNaN(i): judge whether it is NaN
  • Number.isInteger(i): judge whether it is an integer
  • Number.parseInt(str): converts a string to a corresponding number

Object extension (important)

Object abbreviation

ES6 allows you to write variables and functions directly in braces as object properties and methods. Such writing is more concise.

// 1. Attribute abbreviation
let [name, age, sex] = ["xiaowang", 20, "female"];
let p1 = {
    name: name,
    age: age,
    sex: sex
}
console.log(p1);
//In es6, if the key and value of an object are the same, they can be abbreviated
let p2 = {
    name,
    age,
    sex
}
console.log(p2);
//2. Abbreviation of method
let p3 = {
    name,
    age,
    sex,
    do: function () {
        console.log("eat")
    }
}
p3.do();

let p4 = {
    name,
    age,
    sex,
    do() {
        console.log("eat")
    }
}
p4.do();

Property name expression

JavaScript defines the properties of an object in two ways: the dot operator and the bracket operator

However, if an object is defined literally (using braces), only identifiers can be used in ES5, not variables.

That is, in ES5, the key/value key is fixed. In ES6, attribute expressions and key changes are supported

//In ES5, the key/value key is fixed
let p5 = {
    name: "laowang",
    sex: "female"
   
}

// In ES6, the support key changes
let a = "name";
let b = "sex";
let p6 = {
    [a]: "laowang",
    [b + "1"]: "nv"
}
console.log(p6)

//Expressions can also be used to define method names

Object's extension operator

ES2018 introduces this operator into objects.

let { a, b, ...c } = {
    a: 1,
    b: 2,
    c: 3,
    d: 4,
    e: 5
}
console.log(c)

Method of adding object (understand)

Object.is()

Judging whether the objects are equal is equivalent to = = =. Fix the problem of NaN inequality

console.log(Object.is(1, 1))
console.log(Object.is({}, {}))
console.log(Object.is(NaN, NaN))

Merge method Object.assign

let obj1 = { a: 1 };
let obj2 = { b: 2 };
let obj3 = { c: 3 };
let newObj = Object.assign(obj1, obj2, obj3);
console.log(newObj)

New data type (understand)

Symbol

What is a Symbol

ES5 object attribute names are strings, which is easy to cause attribute name conflicts. For example, if you use an object provided by others but want to add a new method to the object, the name of the new method may conflict with the existing method. If there is a mechanism to ensure that the name of each attribute is unique, it will fundamentally prevent the conflict of attribute names. This is why ES6 introduces symbols.

ES6 introduces a new primitive data type Symbol, which represents unique values. It is the seventh data type of the JavaScript language

Use of symbols

  • The Symbol value is generated by the Symbol function.
  • That is to say, there are two types of attribute names of objects. One is the original string, and the other is the new Symbol type. All attribute names that belong to Symbol type are unique, which can ensure that they will not conflict with other attribute names
let s = Symbol();

typeof s
// "symbol"

let s1 = Symbol('foo');
let s2 = Symbol('bar');
s1 // Symbol(foo)
s2 // Symbol(bar)
s1.toString() // "Symbol(foo)"
s2.toString() // "Symbol(bar)"

Symbol represents a unique value

//1. Previous problems
/* let obj = {
      name: "lily",
      todo() {
         console.log("eat");
      }
}
//modify
obj.name = "xiaowang";
obj.todo = () => {
     console.log("someThing~")
}
console.log(obj.name);
obj.todo(); */

//Requirement: make the new attributes and methods not conflict with the previous ones
let name = Symbol("name");
let todo = Symbol("todo");
let obj = {
    name: "Xiao Wang"
}
obj[name] = "Lao Wang"

console.log(obj);
console.log(obj.name)
console.log(obj[name])

Precautions for Symbol

  • The string passed in the Symbol has no meaning, but is only used to describe the character of the Symbol

    {
        let obj1 = {
            name: "lily",//The original object has the name attribute
            age: 18,
        }
        let name = Symbol("name");
        let age = Symbol("age");
        obj1[name] = "xiaowang";
        obj1[age] = 21;
        console.log(obj1)
    }
    
  • Symbol cannot be called with New

    new Symbol();//Symbol is not a constructor
    
  • When converting types, you cannot convert numbers

    console.log(String(Symbol("a")));//Symbol(a)
    console.log(Boolean(Symbol()));//true
    // console.log(Symbol() + 1);//Cannot convert a Symbol value to a number
    // console.log(Number(Symbol()));//Cannot convert a Symbol value to a number
    
  • If you treat Symbol as an object's attribute and method, you must use a variable to store it, otherwise the defined attributes and methods cannot be used

    {
        let obj = {
            name: "lily",//The original object has the name attribute
            age: 18,
        }
        obj[Symbol()] = "bye";//If you set it directly, you will never get this property again
        console.log(obj);
    
        console.log(obj[Symbol()])//undefined
    }
    
  • for in cannot be traversed. You can use the Object.getOwnPropertySymbols method to get it

    {
        let obj = {
            name: "lily",//The original object has the name attribute
            age: 18,
        }
        let name = Symbol();
        obj[name] = "bye";//If you set it directly, you will never get this property again
    
        for (let i in obj) {
            console.log(i);
        }
    
        //You can use the Object.getOwnPropertySymbols method to get
        console.log(Object.getOwnPropertySymbols(obj));//[Symbol()]
    }
    

BigInt

  • JavaScript saves all numbers as 64 bit floating-point numbers, which brings two limitations to the representation of values. First, the accuracy of numerical value can only reach 53 binary bits (equivalent to 16 Decimal bits). For integers greater than this range, JavaScript cannot accurately represent them, which makes JavaScript unsuitable for accurate calculation in science and finance. The second is a value greater than or equal to the 1024 power of 2. JavaScript cannot represent it and will return Infinity.

  • A new data type BigInt (large integer) is introduced to solve this problem. BigInt is only used to represent integers. There is no limit on the number of bits. Integers with any number of bits can be accurately represented.

    // Values with more than 53 binary bits cannot maintain accuracy
    Math.pow(2, 53) === Math.pow(2, 53) + 1 // true
    
    // A value exceeding the 1024 power of 2 cannot be represented
    Math.pow(2, 1024) // Infinity
    
    
    const a = 2172141653n;
    const b = 15346349309n;
    // BigInt can maintain accuracy
    a * b // 33334444555566667777n
    
    // Ordinary integers cannot maintain precision
    Number(a) * Number(b) // 33334444555566670000
    
  • In order to distinguish from the Number type, the data of BigInt type must be suffixed with n.

    1234 // Ordinary integer
    1234n // BigInt
    
    // Operation of BigInt
    1n + 2n // 3n
    
  • BigInt and ordinary integers are two values, and they are not congruent.

    42n === 42 // false
    
  • The typeof operator returns bigint for data of type bigint.

New data structure

Set

What is Set

  • ES6 provides a new data structure Set. It is similar to an array, but the values of members are unique and there are no duplicate values.
  • Set itself is a constructor used to generate a set data structure.
  • The Set function can accept an array (or other data structures with iterable interface) as a parameter to initialize
let st = new Set([1, 2, 3, 4, 4, 3, 3, 1, 5]);
console.log(st);

Properties and methods of Set

  • size returns the length of the Set
  • add adds a value and returns the Set structure itself.
  • delete deletes a value and returns a Boolean value indicating whether the deletion is successful.
  • has returns a Boolean value indicating whether the value is a member of Set
  • clear clears all members and returns no value.
  • keys(): the traverser that returns the key name. Since the Set structure has no key name but only the key value (or the key name and key value are the same value), the behaviors of the keys method and the values method are exactly the same.
  • values(): the iterator that returns the key value
  • entries(): returns the traversal of key value pairs
  • forEach(): use the callback function to traverse each member
// 2. Attribute size
console.log(st.size);

//3. add
st.add(4);
st.add(10);
st.add("hoo");
console.log(st);

//4. Delete
st.delete(2);
console.log(st);

//5. Determine whether an element exists
console.log(st.has(10));
console.log(st.has(11));

//6. Empty all
// st.clear();
// console.log(st);

//7. The behaviors of the keys method and the value method related to loop traversal are consistent
let st2 = new Set(["a", "b", "c", "d"]);
console.log(st2.keys())//"a","b","c","d"
console.log(st2.values())//"a","b","c","d"

for (let a of st2) {
    console.log(a); //"a", "b", "c", "d"
}

//8. Get key value pairs with entries()
console.log(st2.entries());
for (let b of st2.entries()) {
    console.log(b)
}

//9.forEach
st2.forEach((item, index, s) => {
    console.log(item, index, s)
})

Other uses of Set (Practical)

// Remove duplicate members of the array
[...new Set(array)]

//The above method can also be used to remove duplicate characters in the string
[...new Set('ababbc')].join('')
// "abc"

Map

What is a Map

  • JavaScript objects are essentially a collection of key value pairs (Hash structure), but traditionally they can only use strings as keys. This brings great restrictions to its use.
  • To solve this problem, ES6 provides a Map data structure. It is similar to an Object and a collection of key value pairs, but the range of "key" is not limited to strings. Various types of values (including objects) can be used as keys. In other words, the Object structure provides "string value" correspondence, and the Map structure provides "value value" correspondence, which is a more perfect Hash structure implementation. If you need a "key value pair" data structure, Map is more appropriate than Object.
 //Why is there a Map? Because the object attribute name must be a string, not if it is of other types
let p1 = { name: "lily" };
let obj1 = {
    id: 1,
    [p1]: "good"
}
console.log(obj1)

// Map is also a new data structure, similar to object
let mp1 = new Map([
    ["a", 1],
    ["b", 2],
])
console.log(mp1)



let p2 = { name: "lily" };
let mp2 = new Map([
    ["a", 1],
    [p2, 2],
])
console.log(mp2)

Properties and methods of Map

  • The size property returns the total number of members of the Map structure.
  • The set method sets the key value corresponding to the key name key to value, and then returns the entire Map structure. If the key already has a value, the key value will be updated, otherwise the key will be newly generated. The set method returns the current Map object, so it can be written in chain.
  • The get method reads the key value corresponding to the key. If the key cannot be found, it returns undefined.
  • The has method returns a Boolean value indicating whether a key is in the current Map object.
  • The delete method deletes a key and returns true. If the deletion fails, false is returned.
  • The clear method clears all members and returns no value.
  • keys(): the iterator that returns the key name.
  • values(): the iterator that returns the key value.
  • entries(): returns the traversal of all members.
  • forEach(): traverse all members of the Map.

Iterator (understand)

What is an iterator

  • JavaScript's original data structures representing "sets" are mainly arrays and objects. ES6 adds Map and Set. In this way, there are four data sets. Users can also combine them to define their own data structure. For example, the members of the Array are Map and the members of the Map are objects. This requires a unified interface mechanism to deal with all different data structures.
  • Iterator is such a mechanism. It is an interface that provides a unified access mechanism for various data structures. As long as the iterator interface is deployed for any data structure, the traversal operation can be completed (that is, all members of the data structure can be processed in turn).
  • Iterator has three functions: one is to provide a unified and simple access interface for various data structures; Second, the members of the data structure can be arranged in a certain order; Third, ES6 creates a new traversal command for...of loop, and the iterator interface is mainly used for for...of consumption.
let arr = [1, 2, 3];
function Iterator() {
    //Use a counter to save where the processing is now
    let index = 0;
    return {
        next: () => {
            if (index < arr.length) {
                return {
                    value: arr[index++],
                    done: false
                }
            } else {
                return {
                    done: true
                }
            }
        }
    }
}

//Just call the Iterator interface and you can process the members in turn
let it = Iterator(arr);
console.log(it);
console.log(it.next().value);
console.log(it.next().value);
console.log(it.next().value);

Use of iterator

  • A data structure can be iterated as long as the Iterator interface is deployed
  • In ES6, as long as the data structure has the Symbol.iterator attribute, it is considered to be iterative
  • In ES6, many data structures deploy iterator interfaces (Array,set,Map,string)
  • Application scenario:
    • The iterator interface is called by default when deconstructing the assignment
    • The iterator interface is also called by default when the extension operator is used
    • for of uses the iterator interface
    • The object does not have the Iterator interface deployed
let arr = [1, 2, 3, 4, 5];
//arr[Symbol.iterator] is a function block
console.log(arr[Symbol.iterator])
console.dir(arr[Symbol.iterator])

let it = arr[Symbol.iterator]();
//It can be seen that arr has the Iterator interface, so we call it manually
console.log(it)
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());


let str = "abc";
let it2 = str[Symbol.iterator]();
console.log(it2.next());
console.log(it2.next());
console.log(it2.next());
console.log(it2.next());

for...of

  • ES6 uses C + +, Java, c# and Python languages for reference and introduces the for...of loop as a unified method to traverse all data structures.
  • As long as a data structure deploys the Symbol.iterator attribute, it is regarded as having an iterator interface, and its members can be traversed by a for...of loop. That is, the Symbol.iterator method of the data structure is called inside the for...of loop.
  • The for...of loop can use arrays, Set and Map structures, some array like objects (such as arguments object, DOM NodeList object), Generator object later, and strings.
let arr = ["a", "b", "c", "d"];
for (let i of arr) {//for of gets the value
    console.log(i)//a b c d
}
for (let i in arr) {//for in gets the key name
    console.log(i);//0 1 2 3 
}

let str = "abcde";
for (let i of str) {
    console.log(i);
}

//The obj is not iteratable object is not deployed, and the iterator cannot iterate 
let obj = {
    name: "lily"
}
for (let i of obj) {
    console.log(i)
}

For... of and for... in

  • The original for...in loop of JavaScript can only obtain the key name of the object, not the key value directly. ES6 provides a for...of loop that allows traversal to obtain key values. If you want to obtain the index of the array through the for...of loop, you can use the entries method and keys method of the array instance
  • The for...of loop calls the ergodic interface, and the ergodic interface of the array returns only the attributes with numerical indexes. This is different from the for...in loop

Generator (understand)

What is a Generator

  • The Generator function is an asynchronous programming solution provided by ES6. It encapsulates many states internally and is called a state machine Generator
  • Executing the Generator will return an iterator object, which is used to traverse the internal state of the Generator
  • Formally, the Generator function is an ordinary function, but it has two characteristics. First, there is an asterisk between the function keyword and the function name; Second, the yield expression is used inside the function body to define different internal states (yield means "output" in English)
//The definition is different from the ordinary function definition. The yeild keyword is used to define various states internally
function* gen() {
    yield "Status 1";
    yield "Status 2";
    yield "Status 3";
    yield "Status 4";
}

// After calling generator, the iterator object is returned
// In the generator function, it will stop when it encounters yield
let it = gen();
console.log(it);
console.log(it.next());

Generator considerations

  • The internal code of the generator will not be executed immediately. It will be executed only when the next method needs to be called

  • The return result of the yield statement is usually undefined. When the next method is called, the passed parameter content will be used as the return value of the yield statement at startup.

  • After calling the generator, the iterator object is returned. In the generator function, it will stop when it encounters yield until next is run

  • You can use for of to execute gen

  • Object does not have an Iterator interface. You can manually deploy one

    var myIterable = {}
          myIterable[Symbol.iterator] = function* () {
              yield 1
              yield 2
              yield 3
          }
         
    for (let prop of myIterable) {
        console.log(prop)
    }
    

Generator exercises

<button id="btn">Click lucky draw</button>
<script>
    let oBtn = document.getElementById("btn");
    let start = gen();
    oBtn.onclick = function () {
        start.next();
    }
    function draw(count) {
        alert("Remaining" + (count - 1) + "Second chance")
    }
    function* gen(count) {
        //..
        yield draw(5);
        //..
        yield draw(4);
        //..
        yield draw(3);
        //..
        yield draw(2);
        //..
        yield draw(1);
        
        return "";

    }
</script>
/*
  Demand: request a data, then request b data, and then request c data
*/

function* fn() {
    yield setTimeout(() => {
        console.log("a The data succeeded");
        iteratorObj.next(); // Execute the next code
    }, 1000);

    yield setTimeout(() => {
        console.log("b The data succeeded");
        iteratorObj.next(); // Execute the next code
    }, 2000);

    yield setTimeout(() => {
        console.log("c The data succeeded");
        iteratorObj.next(); // Execute the next code
    }, 3000);

    console.log('All data requested back~');
}

const iteratorObj = fn();
iteratorObj.next();

async and await (syntax sugar)

async is used to declare that a function is asynchronous, while await is used to wait for the execution of an asynchronous method to complete

async

  • The async function (derived from ES2017 - ES8) truly solves the problem of asynchronous callback. Synchronous processes express asynchronous operations, which is the syntax sugar of the Generator

  • Syntax:

    async function foo(){

    await asynchronous operation;

    await asynchronous operation;

    }

  • The async function will return a Promise object. If you return a direct quantity in the function, async will encapsulate the direct quantity into a Promise object through Promise.resolve().

async function fn() {
    console.log("fn Function executed");
    return 333;
}

await

  • async replaces the asterisk * of the Generator function and await replaces the yield of the Generator

  • There is no need to call the next method like the Generator. When await waits, the current asynchronous operation will be executed after completion

  • Await is an operator used to form an expression. The operation result of await expression depends on things such as it

    • If it doesn't wait for a Promise object, the operation result of await expression is what it waits for
    • If it waits for a Promise object, await will be busy. It will block the following code, wait for the Promise object to resolve, and then get the value of resolve as the operation result of await expression.
    • If the promise execution result is reject, await has no return value and exits the current async function
  • await will wait for the state of the promise object to change. If it is in the pending state, it will wait all the time. If it is in the resolved state, the following code will be executed automatically. If it is in the rejected state, it will exit the current async function

  • Execute async function, and the return value is a promise object:

    promise object status:

    If there is an internal error in async function (1. Normal error; 2. The internal promise object is in the failed state), the promise object will become in the failed state

    If all the code of async function is executed, it will become a successful state

async function fn() {
    console.log("fn Function executed");
    await 123//Unequal
    await setTimeout(() => {//Unequal
        console.log(222);
    }, 1000)
}
async function fn(){
    console.log("333");
    const re2 = await new Promise((resolve,reject) => {
        setTimeout(function(){
            console.log(222);
            reject("heng")
        },2000)
    })
    console.log(111);
    console.log(re2);
    return "hello";//Return success result value
}
const re = fn();
re.catch((error)=>{console.log(error)})//Resolve the reject status error of await
re.then((data)=>{console.log(data)})//data is the return value of the success result function
console.log(re);
  • Exercise: request a data, request success, request b data

    async function fn() {
            await new Promise((resolve) => {
              setTimeout(() => {
                console.log('a Asynchronous operation completed')
                resolve()
              }, 1000)
            })
            console.log(2)
            await new Promise((resolve) => {
              setTimeout(() => {
                console.log('b Asynchronous operation completed')
                resolve()
              }, 1000)
            })
          }
    fn()
    console.log(1)
    
    
    // The execution effect of the above code is similar to the following code: 
    function* fn() {
        yield setTimeout(() => {
            console.log('a Asynchronous operation completed')
            it.next()
        }, 1000)
        console.log(2)
        yield setTimeout(() => {
            console.log('b Asynchronous operation completed')
            it.next()
        }, 1000)
    }
    let it = fn()
    it.next()
    console.log(1)
    

Class (important)

Origin of class

  • In the JavaScript language, the traditional method of generating instance objects is through constructors

    function Person(name, age) {
        this.name = name;
        this.age = age;
    }
    Person.prototype = {
        course: "html5",
        do() {
            console.log("study");
        }
    }
    let p1 = new Person("lily", 18);
    console.log(p1.name)
    console.log(p1.course)
    p1.do();
    
  • The above writing method is very different from the traditional object-oriented languages (such as C + + and Java), which is easy to confuse the programmers who are new to the language.

  • ES6 provides a writing method closer to the traditional language, and introduces the concept of class as the template of objects. You can define a class by using the class keyword.

  • Basically, the class of ES6 can be regarded as just a syntax sugar. ES5 can do most of its functions. The new class writing method only makes the writing method of object prototype clearer and more like the syntax of object-oriented programming.

  • The constructor method is the default method of the class. It is called automatically when an object instance is generated by the new command. A class must have a constructor method. If it is not explicitly defined, an empty constructor method will be added by default.

  • The static methods or properties of the constructor are directly called by the constructor and defined by static. If static is not added, the declared properties and methods are constructor's

class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    score = 100;//Finally, the instance is constructed
    do() {
        console.log("study");
    }
}
Person.prototype.course = "html5";
//When Person is new, the constructor will be executed
let p1 = new Person("lily", 18);
console.log(p1.__proto__)
console.log(p1.name)
console.log(p1.course)
p1.do(); 

Class inheritance

  • In ES5, we usually write this

    function Person(name, age) {
        this.name = name;
        this.age = age;
    }
    Person.prototype = {
        do() {
            console.log("study");
        }
    }
    function Child(name, age, gender) {
        Person.call(this, name, age, gender)
    }
    
    let cat1 = new Child("Xiao Wang", 19, "male");
    console.log(cat1.name);
    
    
    //Object inheritance
    function extend(obj1, obj2) {
        for (let attr in obj2) {
            obj1[attr] = obj2[attr];
        }
    }
    
  • Class can inherit through the extends keyword, which is much clearer and more convenient than that of ES5 by modifying the prototype chain

  • In subclasses inherited in ES6, if the constructor() is used, it must be initialized with the super() method, so that the following can call the this keyword. super() can only be used in the constructor of a subclass. If it is used in other places, an error will be reported. This is because the subclass's own this object must first be shaped through the constructor of the parent class to obtain the same instance properties and methods as the parent class, and then it will be processed, plus the subclass's own instance properties and methods.

  • If you do not call the super method, the subclass will not get the this object.

 //Class is a keyword that defines a class (a sugar for writing object-oriented syntax, a new syntax)
class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    do() {
        console.log("study");
    }
}
class Child extends Person {
    constructor(name, age, gender) {
        //In subclasses inherited in ES6, if the constructor() is used, it must be initialized with the super() method, so that the following can call the this keyword.
        //super() can only be used in the constructor of subclasses. If it is used elsewhere, an error will be reported
        // This is because the subclass's own this object must first be molded through the constructor of the parent class to obtain the same instance properties and methods as the parent class, and then process it, plus the subclass's own instance properties and methods. If you do not call the super method, the subclass will not get the this object.
        super(name, age);
        this.gender = gender;
    }
}

Promise Foundation (very important)

Promise function

  • Callback function nesting callback function is called callback hell. The code is nested layer by layer and linked. Obviously, the logic is a little more complex, so the program will become difficult to maintain. The code is bloated, the readability is poor, and the coupling degree is too high.
  • In this case, programmers have thought of many solutions (such as modularization of code), but there is still a lot of nesting in process control.
  • In the ES2015 standard, promise standardization solves the problem of JavaScript process operation to a certain extent. Promise object is an asynchronous solution, which can express asynchronous operations in a synchronous process, avoiding layers of nested callback functions (commonly known as' callback Hell ')
setTimeout(() => {
    console.log("a The data request is back~");
    setTimeout(() => {
        console.log("b The data request is back~");
        setTimeout(() => {
            console.log("c The data request is back~");
        }, 3000);
    }, 2000);
}, 1000);

Promise getting started

  • Promise is a constructor. You have familiar methods such as all, reject and resolve. You also have familiar methods such as then and catch on the prototype

  • Promise's constructor receives a parameter, which is a function, and passes in two parameters: resolve and reject, which respectively represent the callback function after successful execution of asynchronous operation and the callback function after failed execution of asynchronous operation.

  • Promise objects have three states: representing the state of asynchronous execution, and the state of the object can only be changed once

    • pending initialization status (asynchronous code is still executing)

      const promise = new Promise((resolve, reject) => {
          // Synchronous call
          //....code
          
          // Perform asynchronous operation / asynchronous code
          setTimeout(() => {
              console.log("setTimeout()");
          }, 1000);
      });
      console.log(promise)
      
    • Resolved / fully successful state (asynchronous code execution is successful). Call the resolve function to change the state of promise object from pending to resolved

      const promise = new Promise((resolve, reject) => {
          setTimeout(() => {
              console.log("setTimeout()");
              resolve('a data');
          }, 1000);
      });
      console.log(promise)
      
    • Rejected status (asynchronous code execution fails). Call the reject function to change the status of the promise object from pending to rejected

      const promise = new Promise((resolve, reject) => {
          // Perform asynchronous operation / asynchronous code
          setTimeout(() => {
              console.log("setTimeout()");
              reject("failed~");
          }, 1000);
      });
      console.log(promise)
      
  • Synchronous asynchronous state of Promise

    The new Promise() function is executed synchronously

    console.log(111)
    const promise = new Promise((resolve, reject) => {
        console.log(222)
        // Synchronous call
        //...code
        // Perform asynchronous operation / asynchronous code
        setTimeout(() => {
            console.log(333)
            console.log("setTimeout()");
            resolve('a data');
        }, 1000);
        console.log(444)
    });
    console.log(555)
    console.log(promise)
    

then and catch methods of Promise

  • Promise.prototype.then captures the promise success status and executes a successful callback

    const promise = new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log("setTimeout()");
            // console.log(333);
            // resolve('a data ');
            reject("failed~");
        }, 1000);
    });
    promise.then(
        (result) => { // Successful callback
            // When the state of the promise object becomes resolved, the current function is executed
            // console.log("resolved 111");
            console.log(result);
        },
        (error) => { // Failed callback
            // When the state of the promise object becomes rejected, the current function is executed
            // console.log("rejected 111");
            console.log(error);
        }
    );
    
  • Promise.prototype.catch captures the state of promise failure and executes the failed callback

    const promise = new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log("setTimeout()");
            // console.log(333);
            // resolve('a data ');
            reject("failed~");
        }, 1000);
    });
    //call chaining 
    promise.then(
        (result) => { // Successful callback
            // When the state of the promise object becomes resolved, the current function is executed
            // console.log("resolved 111");
            console.log(result);
        },
    ).catch(
        (error) => { // Failed callback
            // When the state of the promise object becomes rejected, the current function is executed
            // console.log("rejected 111");
            console.log(error);
        }
    )
    
  • The return value of the then / catch method is a new promise object

    • The new promise object defaults to the success state
    • If the return value of the function accepted by then / catch is a promise object, then the promise of the return value of the then / catch method is the promise object
    • If no promise object is returned, a default success state promise will be created
    • If an internal error is reported, a promise in failure status is returned
    const promise = new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log("setTimeout()");
            // console.log(333);
            resolve('a data');
            // reject("failed ~");
        }, 1000);
    });
    promise.then(
        (result) => { // Successful callback
            // When the state of the promise object becomes resolved, the current function is executed
            // console.log("resolved 111");
            console.log(result);
            return "then";
        },
    ).catch(
        (error) => { // Failed callback
            // When the state of the promise object becomes rejected, the current function is executed
            // console.log("rejected 111");
            console.log(error);
        }
    ).
    then(
        (result) => {
            console.log(111);
            console.log(result)
        },
    ).catch(
        () => {
            console.log(222);
        }
    )
    

Promise exercise

  • Topic 1

    console.log(111);
    
    const promise = new Promise((resolve, reject) => {
        reject();
        console.log(222);
    });
    
    promise
        .then(() => {
        console.log(333);
        return new Promise((resolve) => {
            reject();
        });
    })
        .catch(() => {
        console.log(444);
    })
        .then(() => {
        console.log(555);
        return new Promise((reject, resolve) => {
            reject();
            // resolve();
        });
    })
        .catch(() => {
        console.log(666);
        throw new Error("Wrong report~");
    })
        .then(() => {
        console.log(777);
        throw new Error("Wrong report~");
    })
        .then(() => console.log(888))
        .then(() => console.log(999))
        .catch(() => console.log(101010));
    
    console.log(111111);
    
  • Exercise 2

    /*
      Requirements: setTimeout simulates sending requests
      Request a data, request b data in case of successful request, and request c data in case of successful request
    */
    
    const promise = new Promise((resolve, reject) => {
        // Execute asynchronous code to request a data
        setTimeout(() => {
            console.log("a data ok");
            resolve();
        }, 1000);
    });
    
    promise.then(() => {
        // Request b data
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log("b data ok");
                resolve();
            }, 2000);
        });
    }).then(() => {
        // Request c data
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log("c data ok");
                resolve();
            }, 3000);
        });
    }).then(() => {
        console.log('All data requested~');
    })
    
    
  • Exercise 3

    /*
      Requirements: request three data at the same time. Only when all requests are successful can they be OK. As long as one fails, it will fail
    */
    
    /*
    const promise = new Promise((resolve, reject) => {
        let successNum = 0;
    
        setTimeout(() => {
            console.log("a Data ok ");
            reject();
            successNum++;
            if (successNum === 3) {
                resolve();
            }
        }, 1000);
    
        setTimeout(() => {
            console.log("b Data ok ");
            successNum++;
            if (successNum === 3) {
                resolve();
            }
        }, 2000);
    
        setTimeout(() => {
            console.log("c Data ok ");
            successNum++;
            if (successNum === 3) {
                resolve();
            }
        }, 3000);
    });
    
    promise
        .then(() => console.log("All succeeded ~ "))
        .catch(() => console.log("Failed ~ "); 
    */
        
    const promise1 = new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log("a data ok");
            resolve();
        }, 1000);
    });
    
    const promise2 = new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log("b data ok");
            reject();
        }, 2000);
    });
    
    const promise3 = new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log("c data ok");
            resolve();
        }, 3000);
    });
    
    const promise = Promise.all([promise1, promise2, promise3]);
    
    promise
        .then(() => console.log("All succeeded~"))
        .catch(() => console.log("failed~"));
    
    

then and catch methods of Promise

If promise becomes success / failure, it will be triggered, but pending will not be triggered

const promise = new Promise((resolve, reject) => {
    // resolve(111);
    // reject(222);
});
// If promise becomes success / failure, it will be triggered, but pending will not be triggered
promise.finally(() => {
    console.log("finally()");
});

Other Promise methods

  • Promise.all ([promise 1,...]) passes in n promise objects. Only when the states of N promise objects are successful can they succeed. As long as one fails, it will fail
  • Promise.resolve() returns a promise object with a success status
  • Promise.reject() returns an object with a failed status
  • Promise.allsettled ([promise 1,...]) passes in n promise objects, and all the result values are obtained when the states of all n promise objects change

Dynamic import

  • The parameter of the import function specifies the location of the module to be loaded.
  • The import() function can accept whatever parameters the Import command can accept. The main difference between the two is that the latter is dynamic loading
  • import() returns a Promise object.
  • It is executed at runtime, that is, when it runs to this sentence, the specified module will be loaded
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Title</title>
  </head>
  <body>
    <button id="btn">Button</button>
    <script type="text/javascript">
      document.getElementById("btn").onclick = function () {
        import("./a.js")
          .then(() => {
            console.log(111);
          })
          .catch(() => {
            console.log(222);
          });
      };
    </script>
  </body>
</html>
//a.js
console.log('a.js Yes~');

Tags: Java Javascript Front-end ECMAScript

Posted on Thu, 09 Sep 2021 23:40:24 -0400 by Hitch54