ES7-11


ES7

Array.prototype.includes

概述

Includes 方法用来检测数组中是否包含某个元素,返回布尔类型值;

判断数组中是否包含某元素,语法:arr.includes(元素值);

代码

let arr = [1,2,3,4,5]; 
console.log(arr.includes(1));//true

指数操作符

概述

在 ES7 中引入指数运算符「**」,用来实现幂运算,功能与 Math.pow 结果相同;

幂运算的简化写法,例如:2的10次方:2**10;

代码

console.log(Math.pow(2,10)) //1024
console.log(2**10);//1024

ES8

async await

可以参考下面网址的教程

Async/await (javascript.info)

概述

async 和 await 两种语法结合可以让异步代码看起来像同步代码一样;简化异步函数的写法;

async函数

1.async 函数的返回值为 promise 对象

2.promise 对象的结果由 async 函数执行的返回值决定

代码

1.return返回的是非promise对象,,则async返回成功的promise,且该promise对象中的状态为成功,值为返回值。

async function fn(){
    return "hello";
}
const result = fn();
console.log(result);

QQ20220117110217.png

2.函数中抛出错误的话,返回的也是promise,不过状态为错误!

async function fn(){
    throw new Error("新错误!!");
}
const result = fn();
console.log(result);

QQ20220117110512.png

3.函数return的是promise对象的话,async返回的promise对象与return的promise对象一致!

async function fn(){
    return new Promise((resolve,reject)=>{
        resolve("返回的promise是成功的promise!!");
    })
}
const result = fn();
console.log(result);

QQ20220117110824.png

若返回的promise是reject,则async返回的也是失败类型的promise

async function fn(){
    return new Promise((resolve,reject)=>{
        reject("失败了!!");
    })
}
const result = fn();
console.log(result);

QQ20220117111610.png

await表达式

概述

1.await 必须写在 async 函数中;

2.await 右侧的表达式一般为 promise 对象;

3.await 返回的是 promise 成功的值;

4.await 的 promise 失败了, 就会抛出异常, 需要通过 try...catch 捕获处理

代码

1.返回的promise是成功的

// async函数 + await表达式:异步函数 
// 创建Prmise对象 
const p = new Promise((resolve,reject)=>{ 
    resolve("成功啦!"); 
})
async function fn(){ 
    // await 返回的是 promise 成功的值 
    let result = await p; 
    console.log(result); // 成功啦! 
}
fn();

2.返回的promise是失败的话,就需要用try...catch来捕获

const p = new Promise((resolve,reject) => {
    reject("返回的promise是失败的!")
})

async function main(){
    try{
        let result = await p;
        console.log(result);
    }catch(e){
        console.log("捕获到异常了!")
        console.log(e);
    }
}
main();

QQ20220117120018.png

async和await结合案例

案例1----读取文件

// 导入模块 
const fs = require("fs"); 
// 读取 
function readText() { 
    return new Promise((resolve, reject) => { 
        fs.readFile("../resources/text.txt", (err, data) => {
            //如果失败 
            if (err) reject(err); 
            //如果成功 resolve(data); 
        }) 
    }) 
}

function readTest1() {
    return new Promise((resolve, reject) => { 
        fs.readFile("../resources/test1.txt", (err, data) => { 
            //如果失败 if (err) reject(err); //如果成功 resolve(data); 
        }) 
    }) 
}

function readTest2() { 
    return new Promise((resolve, reject) => { 
        fs.readFile("../resources/test2.txt", (err, data) => { 
            //如果失败 
            if (err) reject(err); //如果成功 resolve(data); 
        }) 
    }) 
}

//声明一个 async 函数 
async function main(){ 
    //获取为学内容 
    let t0 = await readText(); //因为返回的都是promise对象,所以可以直接用await读取promise成功状态下的值
    //获取插秧诗内容 
    let t1 = await readTest1(); 
    // 获取观书有感 
    let t2 = await readTest2(); 
    console.log(t0.toString()); 
    console.log(t1.toString()); 
    console.log(t2.toString()); 
}
main();

案例2----发送ajax请求

function sendAjax(url){ 
    return new Promise((resolve,reject)=>{ 
        // 1、创建对象 
        const x = new XMLHttpRequest(); 
        // 2、初始化 
        x.open("GET",url); 
        // 3、发送 
        x.send(); 
        // 4、事件绑定 
        x.onreadystatechange = function(){ 
            if(x.readyState == 4){ 
                if(x.status>=200 && x.status<=299){ 
                    // 成功 
                    resolve(x.response); 
                }else{
                    // 失败 
                    reject(x.status); 
                } 
            } 
        } 
    }); 
}

async function main(){ 
    let result = await sendAjax("https://api.apiopen.top/getJoke"); 
    console.log(result); 
}
main();

ES9

spred拓展运算符与rest参数

概述

Rest 参数与 spread 扩展运算符在 ES6 中已经引入,不过 ES6 中只针对于数组,在 ES9 中为对象提供了像数组一样的 rest 参数和扩展运算符;

1.rest参数的使用场景

function connect({host,port,username,password}){//这里参数接受的是一个对象
    console.log(host);
    console.log(port);
    console.log(username);
    console.log(password);
}
connect({
    host:'127.0.0.1',
    port:3306,
    username:'root',
    password:'root'
});

参数接受的是一个对象时,按照这样的写法没有什么问题,效果如下:

QQ20220120101208.png

rest参数可以把剩下的参数整合到一个对象中,比如把username和password整合到user对象中,写法如下:

function connect({host,port,...user}){
    console.log(host);
    console.log(port);
    console.log(user);//这里的user就是一个对象
}
connect({
    host:'127.0.0.1',
    port:3306,
    username:'root',
    password:'root'
});

结果如下

QQ20220120101528.png

2.拓展运算符使得对象合并

const skillOne = { q: '天音波' }
const skillTwo = { w: '金钟罩' }
const skillThree = { e: '天雷破' }
const skillFour = { r: '猛龙摆尾',  z: '胡说八道' }
const mangseng = {
    ...skillOne,
    ...skillTwo,
    ...skillThree,
    ...skillFour
};
console.log(mangseng)

结果:

QQ20220120103740.png

正则拓展,命名捕获分组

概述

ES9 允许命名捕获组使用符号『?』,这样获取捕获结果可读性更强;

代码

普通方式提取正则表达式中的必要字符串可以通过数组下标的形式:

let str = '訾博';
//需求:提取url和标签内文本
const reg = /(.*)<\/a>/;

const result = reg.exec(str);
console.log(result);
console.log(result[1])//http://www.baidu.com

结果

QQ20220120104342.png

不过这么提取会有一个弊端,就是数组下标作为提取的依据,变量名的表面意义并没有用上,即我们调用数组时有可能并不知道数组中的第一个元素对应的是哪个变量。

这时我们就可以对正则提取出来的元素进行命名,这样更方便提取,被命名的元素都会出现在groups中。

    let str = '訾博';
    const reg1 = /(?.*)<\/a>/;
    const result1 = reg1.exec(str);
    console.log(result1);
    //通过变量名提取字符串
    console.log(result1.groups.url);
    console.log(result1.groups.text);
    //当然也可以通过数组名来提取字符串
    console.log("通过数组调用")
    console.log(result1[1])
    console.log(result1[2])

结果如下:

QQ20220120104908.png

正则拓展,反向断言

概述

ES9 支持反向断言,通过对匹配结果前面的内容进行判断,对匹配进行筛选,这就是反向断言。正向断言就是根据后面的内容进行判断。

代码

需求:我们想要提取啦啦啦前面的,你知道么后面的555,该如何提取?通过正则表达式

1.使用正向断言

let str = "JS5201314你知道么555啦啦啦";
const reg = /\d+(?=啦)/; // 前面是数字后面是啦
const result = reg.exec(str);
console.log(result);

2.使用反向断言

let str = "JS5201314你知道么555啦啦啦";
const reg1 = /(?<=么)\d+/; // 后面是数字前面是么
const result1 = reg.exec(str);
console.log(result1);

正则拓展:dotAll 模式

概述

正则表达式中点.匹配除回车外的任何单字符,标记『s』改变这种行为,允许行终止符出现;

代码

想取出电影名和上映日期

    let str = `  `;

    //旧写法
    const reg = /
  • \s+(.*?)<\/a>\s+

    (.*?)<\/p>/;//加\s是为了匹配换行符,这点就比较讨厌 // const reg = /

  • .*?(?.*?)<\/a>.*?

    (?

  • 结果如下:

    QQ20220120112200.png

    使用dotAll的话,匹配换行符可以直接使用.*?来进行,十分方便!

    const reg = /
  • .*?(.*?)<\/a>.*?

    (.*?)<\/p>/gs;//末尾加上gs代表全局匹配 let result; let data = []; while(result = reg.exec(str)){ data.push({title:result[1],time:result[2]}); } console.log(data);

  • 结果如下:

    QQ20220120112424.png

    ES10

    Object.fromEntries将二维数组或者map转换为对象

    1.将二维数组转换为对象

    const result = Object.fromEntries([
        ["name","訾博"],
        ["age",24],
    ]);
    console.log(result);
    

    结果:

    QQ20220120112946.png

    2.将map转换为对象

    const m = new Mao();
    m.set("name","阿福");
    m.set("age",26);
    const result = Object.fromEntries(m);
    console.log(result);
    

    结果:

    QQ20220120113132.png

    这里的方法和ES8中的方法Object.entries()有对应,ES8中的Object.entries()将对象转换为二维数组

    const afu={
        name:"阿福",
        age:"22"
    };
    const arr = Object.entries(afu);
    console.log(arr);
    

    QQ20220120113428.png

    trimStart和trimEnd

    在之前的语法中trim可以清楚字符串左侧和右侧的空白字符,而trimStart是指定清除左侧的,trimEnd是指定清除右侧的。

    let str = " zibo ";
    console.log(str.trimLeft());
    console.log(str.trimRight());
    console.log(str.trimStart());
    console.log(str.trimEnd());
    console.log(str.trim())
    

    结果如下:

    QQ20220120113825.png

    数组拓展的方法:flat

    用于将多维数组转化为低维数组

    flat(),里面传递的参数默认为1,参数表明把数组降低多少维度。

    const arr=[1,2,3,4[5,6[7,8,9]]]//这是一个三维数组
    //如果想降低一维成为二维数组,则直接调用flat即可
    console.log("二维数组:")
    console.log(arr.flat());
    console.log("一维数组:")
    console.log(arr.flat(1));
    

    QQ20220120114629.png

    ES11

    对象的私有属性

    概述

    对象中的属性前面加上#后,就代表是私有属性,这样就不能通过外部直接调用来获取私有属性了

    class Person{
        name;
        #age;
        #weight;
        
        constructor(name,age,weight){
            this.name=name;
            this.#age=age;
            this.#weight=weight;
        }
    	
    	getAge(){
            return #age;
        }
    }
    
    //实例化
    const girl = new Person('小红',18,'45kg');
    console.log(girl.name);//可以正常打印
    //但如果直接读取私有属性的话,就会报错
    console.log(girl.#age);
    

    会报错:

    QQ20220120120538.png

    把读取私有属性的语句注释掉之后:

    QQ20220120120538.png

    读取私有属性可以通过类内部的方法进行调用:

    console.log(girl.getAge());
    

    QQ20220120120801.png

    字符串拓展:String.prototype.matchAll()

    概述

    该方法可以快捷的获取字符串中的匹配值,而不用像之前一样使用循环来实现。

        let str = `  `;
        const reg = /
  • .*?(?.*?)<\/a>.*?

    (?

  • 得到的是一个可迭代对象

    QQ20220120145649.png

    对于这个可迭代对象,我们可以使用for of进行遍历,同样也可以使用拓展运算符讲其转换为数组

    const result = str.matchAll(reg);
    let arr = [...result];
    console.log(arr)
    

    QQ20220120150233.png

    也可以迭代,使用for..of..

    可选链操作符

    概述

    如果存在则往下走,省略对对象是否传入的层层判断

    代码

    假如一个函数接受的参数是一个配置对象,我们想读出配置对象里的某个属性,那么使用js的话需要层层判断,首先需要判断配置对象是否传入接着再来判断对象里的属性是否初始化等等...

    1.传统写法

    function main(config){
        const dbHost = config && config.db && config.db.host;//只有前面的都存在才会读取config.db.host
        console.log(dbHost);
    }
    main({
        db:{
            host:`192.168.1.100`,
            username:`root`
        },
        cache:{
            host:`192.168.1.200`,
            username:`admin`
        }
    })
    

    QQ20220120152523.png

    如果不判断,就直接打印的话,若传入的对象没有该属性,就会报错

    function main(config){
        const dbHost =config.db.host;
        console.log(dbHost);
    }
    main({
        cache:{
            host:`192.168.1.200`,
            username:`admin`
        }
    })
    

    QQ20220120152655.png

    若是先前有判断的写法的话,就会显示undefined,并不会报错!

    2.使用可选链操作符就简便的多

    (1)若没有相应的属性

        function main(config){
            const dbHost = config?.db?.host;
            console.log(dbHost);
        }
        main({
            cache:{
                host:`192.168.1.200`,
                username:`admin`
            }
        })
    

    QQ20220120152843.png

    (2)若有相应的属性

        function main(config){
            const dbHost = config?.db?.host;
            console.log(dbHost);
        }
        main({
            db:{
                host:`192.168.1.100`,
                    username:`root`
        },
        cache:{
            host:`192.168.1.200`,
                username:`admin`
        }
        })
    

    成功打印:

    QQ20220120152938.png

    动态import

    概述

    实现模块的懒加载,用到的时候再导入,传统的import是静态导入,即加载import语句的时候就把对应的模块导入进来了。

    代码

    hello.js

    export function hello(){ 
        alert('Hello'); 
    }
    

    html文件

     
     
        
             
             
            动态 import  
         
        
             
             
         
    
    

    1.静态导入方式

    app.js

    import * as m1 from "./hello.js"; // 传统静态导入
    const btn = document.getElementById('btn');
    btn.onclik = function(){
        m1.hello();
    }
    

    2.动态导入方式

    app.js

    btn.onclick = function(){
        import('./hello.js').then(module => {//动态导入返回的是一个promise对象
            module.hello();
         });
    }
    

    BigInt

    概述

    更大的整数,使用方法是声明时在普通的数字后面加n即可,也可以使用BigInt()函数来讲普通类型的数字转换为大整型的数字。

    代码

    1.声明

    let n =521n;
    console.log(n,typeof(n));
    

    QQ20220120153854.png

    2.使用函数转换普通数字

    let n =123;
    console.log(BigInt(n));
    console.log(BigInt(1.2));//不能转换浮点型数字,这样会报错!
    

    3.BigInt主要用于更大整数的运算

    let max = Number.MAX_SAFE_INTEGER;//9007199254740991
    console.log(max);
    console.log(max + 1);
    console.log(max + 2);
    
    console.log(BigInt(max))
    //console.log(BigInt(max)+1)  这么写会报错,因为BigInt类型的值无法和普通int做运算,必须把所有操作数都转换为BigInt才可以进行运算
    console.log(BigInt(max) + BigInt(1));
    console.log(BigInt(max) + BigInt(2));
    

    QQ20220120154522.png

    golbalThis对象

    概述

    始终指向全局对象window

    代码

    console.log(gobalThis);
    

    QQ20220120155537.png