【ES7-ES11】新特性

89 阅读13分钟

ES7

一、indexOf方法

1、在数组中

indexOf方法用于查找一个元素在数组中的位置。如果该元素在数组中存在,则返回其第一个出现的索引(从0开始计数);如果不存在,则返回-1。 语法

	array.indexOf(searchElement[, fromIndex])
  • searchElement:要在数组中查找的元素。
  • fromIndex(可选):表示从该索引处开始查找,默认为0。如果索引值大于或等于数组的长度,则整个数组都会被搜索。如果为负值,则将其视为从数组末尾开始的第几位(但不是从-1开始计算,而是从数组长度减1开始,然后减去该负值,如果计算出的索引小于0,则整个数组都会被搜索)。

示例

let array = [2, 5, 9, 1, 2];  
console.log(array.indexOf(2)); // 输出: 0  
console.log(array.indexOf(7)); // 输出: -1  
console.log(array.indexOf(2, 1)); // 输出: 4,因为从索引1开始查找,第二个2的索引是4

2、在字符串中

indexOf方法在字符串中,indexOf方法用于查找一个子字符串在字符串中首次出现的位置(索引)。如果该子字符串存在,则返回其第一个字符的索引;如果不存在,则返回-1。

语法

    string.indexOf(searchValue[, fromIndex])
  • searchValue:要在字符串中查找的子字符串。
  • fromIndex(可选):表示从该索引处开始查找,默认为0。如果索引值大于或等于字符串的长度,则整个字符串都会被搜索。如果为负值,则将其视为从字符串末尾开始的第几位(但计算方式与数组略有不同,具体为:fromIndex = string.length + fromIndex,如果计算出的索引小于0,则整个字符串都会被搜索)。但需要注意的是,在字符串中,fromIndex为负数的情况并不常用,且可能因浏览器或JavaScript引擎的不同而有所差异。

示例

let str = "Hello, world!";  
console.log(str.indexOf("world")); // 输出: 7  
console.log(str.indexOf("o")); // 输出: 4,因为"o"在字符串中首次出现的索引是4  
console.log(str.indexOf("o", 5)); // 输出: 8,因为从索引5开始查找,"o"在字符串中第二次出现的索引是8

3、注意事项

  1. indexOf方法使用严格相等运算符(===)来比较元素或子字符串。因此,对于数组来说,如果数组元素是对象,那么即使两个对象的内容相同,indexOf方法也会返回-1,因为它们在内存中的引用是不同的。
  2. 对于字符串来说,indexOf方法是区分大小写的。例如,str.indexOf("Hello")str.indexOf("hello")的结果是不同的。
  3. 当在数组中查找NaN时,indexOf方法会失败,因为NaN与任何值(包括它自身)都不相等。在这种情况下,可以使用Array.prototype.includes()方法,它认为两个NaN是相等的。

includes 方法是 JavaScript 数组和字符串对象的一个方法,用于判断一个数组或字符串是否包含一个指定的元素或子字符串。如果包含,则返回 true;否则返回 false

 二、includes

1、数组中

在数组中,includes 方法用于检查数组是否包含某个元素,并根据情况返回 true 或 false语法

  • valueToFind:需要查找的元素值。
  • fromIndex(可选):表示从该索引处开始查找,默认为0。如果索引值大于或等于数组的长度,则返回 false。如果为负值,则将其视为从数组末尾开始的第几位(但不是从-1开始计算,而是从数组长度减1开始,然后减去该负值,如果计算出的索引小于0,则整个数组都会被搜索)。 示例
let array = [1, 2, 3, 4, 5];  
console.log(array.includes(3)); // 输出: true  
console.log(array.includes(10)); // 输出: false  
console.log(array.includes(3, -2)); // 输出: true,因为从倒数第二个元素开始查找,3存在于数组中

2、字符串中

字符串中,includes 方法用于判断一个字符串是否包含另一个子字符串,并根据情况返回 true 或 false语法

string.includes(searchString[, position])
  • searchString:需要在字符串中查找的子字符串。
  • position(可选):表示从该索引处开始查找,默认为0。如果索引值大于或等于字符串的长度,则返回 false。如果为负值,则将其视为从字符串末尾开始的第几位(但计算方式与数组略有不同,且这种用法在字符串中并不常见,因为字符串索引不允许为负数)。 示例
let str = "Hello, world!";  
console.log(str.includes("world")); // 输出: true  
console.log(str.includes("o")); // 输出: true,因为"o"是子字符串,存在于字符串中  
console.log(str.includes("o", 5)); // 输出: true,因为从索引5开始查找,"o"在字符串中仍然存在(出现在索引7处)  
// 注意:在字符串中,通常不会使用负数的position值,因为这会导致错误或不符合预期的行为。

3、注意事项

  1. includes 方法对大小写敏感。例如,str.includes("Hello") 和 str.includes("hello") 的结果是不同的。
  2. includes 方法使用严格相等运算符(===)的等价逻辑来比较元素或子字符串。但是,对于 NaN 的比较,includes 方法认为两个 NaN 是相等的,这与 indexOf 方法不同(indexOf 方法认为 NaN 不等于任何值,包括它自身)。
  3. 在数组中查找对象时,即使两个对象的内容相同(即它们的属性名和属性值都相同),includes 方法也会返回 false,因为它们在内存中的引用是不同的。要比较对象的内容是否相同,需要使用其他方法(如深度比较函数)。

三、**

运算符用于计算一个数的指数幂

let a = 2;
let b = 3;                       
let result1 = a ** b; // 8        
let result2 = 2 ** 3 ** 2; // 512 
let c = 1.5;                      
c **= 2; // c 的值变为 2.25

ES8 async和await

ES8(ECMAScript 2017)引入了 async 和 await 关键字,它们是对 JavaScript 中处理异步操作的一种更简洁和直观的方式。这两个关键字使得异步代码看起来更像是同步代码,从而大大简化了异步编程的复杂性。

一、async 关键字

async 关键字用于声明一个异步函数。它会隐式地返回一个 Promise 对象。如果函数正常结束,则 Promise 会被解析(resolved);如果函数抛出异常,则 Promise 会被拒绝(rejected)。

如果结果不是一个 Promise类型对象,就会隐式地返回一个成功的Promise对象

async function fn(){
    // 返回一个字符串
     return '隐式返回成功的Promise';
    // 返回的结果不是一个 Promise 类型的对象, 返回的结果就是成功 Promise 对象
}

const result = fn();
console.log(result);

返回结果设置为空,则返回一个隐式返回成功的Promise,值为undefined

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

抛出错误, 返回的结果是一个失败的 Promise

async function fn(){
  throw new Error('出错啦!');
}

设计结果是Promise对象

1、方式一

 async function fn(){
    return new Promise((resolve, reject)=>{
        resolve('成功的数据');
        // reject("失败的错误");
    });
}
const result = fn();
console.log(result);

2、方式二:使用then

 async function fn(){
    return new Promise((resolve, reject)=>{
        resolve('成功的数据');
        // reject("失败的错误");
    });
}
const result = fn();
//调用 then 方法
result.then(value => {
    console.log(value);
}, reason => {
    console.warn(reason);
})

二、await 关键字

await 关键字只能在 async 函数内部使用。它用于等待一个 Promise 完成,并返回 Promise 的结果。如果 Promise 被拒绝,则会抛出异常,可以用 try...catch 语句捕获。

1、一般使用

async function myFunction() {  
    let promise = new Promise((resolve, reject) => {  
        setTimeout(() => resolve('Done!'), 1000);  
    });  
    let result = await promise; // 等待 Promise 完成  
    alert(result); // 输出: Done!  
}  
myFunction();

1、使用 async 和 await 处理多个异步操作

async 和 await 使得处理多个异步操作变得更加简单。你可以使用 await 依次等待每个异步操作完成,而不需要使用嵌套的 .then() 方法。

	async function fetchData() {  
	    try {  
	        let response1 = await fetch('https://api.example.com/data1');  
	        let data1 = await response1.json();  
	        let response2 = await fetch('https://api.example.com/data2');  
	        let data2 = await response2.json();  
	        console.log(data1, data2);  
	    } catch (error) {  
	        console.error('Error fetching data:', error);  
	    }  
	}  
	fetchData();

3、并行处理多个异步操作

虽然 await 会按顺序等待每个 Promise 完成,但你可以使用 Promise.all() 来并行处理多个异步操作。

	async function fetchData() {  
	    try {  
	        let promise1 = fetch('https://api.example.com/data1').then(response => response.json());  
	        let promise2 = fetch('https://api.example.com/data2').then(response => response.json());  
	        let [data1, data2] = await Promise.all([promise1, promise2]);  
	        console.log(data1, data2);  
	    } catch (error) {  
	        console.error('Error fetching data:', error);  
	    }  
	}  
	fetchData();

4、总结

  • async 关键字用于声明一个返回 Promise 的异步函数。
  • await 关键字用于等待一个 Promise 完成,并返回其结果。它只能在 async 函数内部使用。
  • 使用 try...catch 语句来捕获 await 等待的 Promise 被拒绝时的异常。
  • 可以使用 Promise.all() 来并行处理多个异步操作。 async 和 await 使得异步代码更加直观和易于理解,是现代 JavaScript 异步编程的一种重要工具。

三、对象方法扩展

1、获取所有的键Object.keys 2、获取所有的值Object.values 3、获取所有的键值对Object.entries 4、创建map 5、对象属性的描述对象

//声明对象
const school = {
    name:"尚硅谷",
    cities:['北京','上海','深圳'],
    xueke: ['前端','Java','大数据','运维']
};

// 获取对象所有的键
console.log(Object.keys(school));
// 获取对象所有的值
console.log(Object.values(school));
// entries  获取所有的键值对
console.log(Object.entries(school));
// 创建 Map
const m = new Map(Object.entries(school));
console.log(m.get('cities'));

// 对象属性的描述对象
console.log(Object.getOwnPropertyDescriptors(school));
const obj = Object.create(null, {
    name: {
        //设置值
        value: '尚硅谷',
        //属性特性
        writable: true,
        configurable: true,
        enumerable: true
    } 
});

案例

1、async和await读取文件

//1. 引入 fs 模块
const fs = require("fs");

//读取文件1
    function readFile1() {
    return new Promise((resolve, reject) => {
        fs.readFile("./resources/文件1.md", (err, data) => {
            //如果失败
            if (err) reject(err);
            //如果成功
            resolve(data);
        })
    })
}

function readFile2() {
    return new Promise((resolve, reject) => {
        fs.readFile("./resources/文件2.md", (err, data) => {
            //如果失败
            if (err) reject(err);
            //如果成功
            resolve(data);
        })
    })
}

function readFile3() {
    return new Promise((resolve, reject) => {
        fs.readFile("./resources/文件3.md", (err, data) => {
            //如果失败
            if (err) reject(err);
            //如果成功
            resolve(data);
        })
    })
}

//声明一个 async 函数
async function main(){
try {  
         //获取文件1内容
        let File1 = await readFile1();
        //获取文件2内容
        let File2 = await readFile2();
        // 获取文件3有感
        let File3 = await readFile3();

        console.log(File1.toString());
        console.log(File2.toString());
        console.log(File3.toString());
    } catch (error) {  
        console.error("读取文件时出错:", error.message)
    }  
}

main();

2、async和await发送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 < 300) {  
                    // 成功啦  
                    try {  
                        const responseData = JSON.parse(x.responseText);  
                        resolve(responseData); // 将解析后的数据传递给Promise的resolve函数  
                    } catch (parseError) {  
                        reject(new Error('Error parsing JSON response: ' + parseError.message));  
                    }  
                } else {  
                    // 请求失败  
                    reject(new Error('Request failed with status: ' + x.status));  
                }  
            }  
        };  
  
        // 处理网络错误(如请求被中断)  
        x.onerror = function () {  
            reject(new Error('Network error occurred during the request.'));  
        };  
    });  
}  
  
// 使用示例   then
const weatherAPIUrl = 'https://www.tianqiapi.com/api/?version=v1&city=%E5%8C%97%E4%BA%AC&appid=23941491&appsecret=TXoD5e8P';  
sendAJAX(weatherAPIUrl)  
    .then(data => {  
        console.log('Weather data received:', data);  
        // 在这里处理天气数据  
    })  
    .catch(error => {  
        console.error('Error fetching weather data:', error.message);  
    });

ES9

一、对象展开

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

 //rest 参数
function connect({host, port, ...user}){
    console.log(host);
    console.log(port);
    console.log(user);
}

connect({
    host: '127.0.0.1',
    port: 3306,
    username: 'root',
    password: 'root',
    type: 'master'
});


//对象合并
const skillOne = {
    q: '天音波'
}

const skillTwo = {
    w: '金钟罩'
}

const skillThree = {
    e: '天雷破'
}
const skillFour = {
    r: '猛龙摆尾'
}

const mangseng = {...skillOne, ...skillTwo, ...skillThree, ...skillFour};

console.log(mangseng)

二、正则表达式

1、有分组

//声明一个字符串
let str = '<a href="http://www.atguigu.com">尚硅谷</a>';

// //提取 url 与 『标签文本』
// 捕获
const reg = /<a href="(.*)">(.*)<\/a>/;

// //执行
const result = reg.exec(str);

console.log(result);
console.log(result[1]);
console.log(result[2]);

2、无分组(进行命名)

  let str = '<a href="http://www.atguigu.com">尚硅谷</a>';
//分组命名
const reg = /<a href="(?<url>.*)">(?<text>.*)<\/a>/;
const result = reg.exec(str);
console.log(result.groups.url);
console.log(result.groups.text);

正则断言(正向断言、反向断言)

1、正向断言

 //声明字符串
let str = 'JS5211314你知道么555啦啦啦';
//正向断言
const reg = /\d+(?=啦)/;  //判断后面是不是啦
const result = reg.exec(str); //555
console.log(result);

2、反向断言

let str = 'JS5211314你知道么555啦啦啦';
//反向断言
const reg = /(?<=么)\d+/; //判断前面是不是么
const result = reg.exec(str); //555
console.log(result);

3、正则扩展-dotAll模式 dot . 元字符 除换行符以外的任意单个字符

let str = `
<ul>
    <li>
        <a>肖生克的救赎</a>
        <p>上映日期: 1994-09-10</p>
    </li>
    <li>
        <a>阿甘正传</a>
        <p>上映日期: 1994-07-06</p>
    </li>
</ul>`;
//声明正则
// const reg = /<li>\s+<a>(.*?)<\/a>\s+<p>(.*?)<\/p>/;
const reg = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/gs;
//执行匹配
// const result = reg.exec(str);
let result;
let data = [];
while(result = reg.exec(str)){
    data.push({title: result[1], time: result[2]});
}
//输出结果
console.log(data);

ES10

一、Object.fromEntries

1、Object.fromEntries将二维数组转化为对象

2、补充:在ES8中 Object.entrie将对象转化为二维数组

//二维数组
const result = Object.fromEntries([
    ['name','尚硅谷'],
    ['xueke', 'Java,大数据,前端,云计算']
]);

//Map
const m = new Map();
m.set('name','ATGUIGU');
const result2 = Object.fromEntries(m);
console.log(result2);


//Object.entries ES8
const arr = Object.entries({
    name: "尚硅谷"
})
console.log(arr);

二、trim、trimStart 与 trimEnd清除空白字符

1、trim清除两侧的空白字符

2、trimStart清除左侧的空白字符串

3、trimEnd清除右侧的空白字符串

 let str = '   iloveyou   ';
console.log(str);
console.log(str.trim());
console.log(str.trim().length);
console.log(str.trimStart());
console.log(str.trimStart().length);
console.log(str.trimEnd());

三、flat 与 flatMap

1、flat 将多维数组转换为低平数组

 //flat 平
//将多维数组转化为低位数组
const arr = [1,2,3,4,[5,6]];
console.log(arr.flat(2));  
const arr = [1,2,3,4,[5,6,[7,8,9]]];
//参数为深度 是一个数字
console.log(arr.flat(2)); 

2、flatMap的每个结果进行唯独的操作

const arr = [1,2,3,4];
const result = arr.flatMap(item => [item * 10]);
console.log(result);

四、Symbol.prototype.description

获取Symbol的字符串描述

 //创建 Symbol
let s = Symbol('尚硅谷');
console.log(s);  //Symbol(尚硅谷)
console.log(s.description); //尚硅谷

ES11

一、私有属性

在对象前面加#可以实现私有属性,使用一般获取方法会报错

class Person{
    //公有属性
    name;
    //私有属性
    #age;
    #weight;
    //构造方法
    constructor(name, age, weight){
        this.name = name;
        this.#age = age;
        this.#weight = weight;
    }

    intro(){    //闭包
        console.log(this.name);
        console.log(this.#age);
        console.log(this.#weight);
    }
}
//实例化
const girl = new Person('晓红', 18, '45kg');
// console.log(girl.name);
// console.log(girl.#age); //报错
// console.log(girl.#weight);//报错
girl.intro();  //调取闭包

二、Promise.allSettled

接收一个Promise的数组,返回一个Promise的对象,返回的结果一定是Promisee的成功的状态,返回的值是Promise的状态和结果

 //声明两个promise对象
        const p1 = new Promise((resolve, reject)=>{
            setTimeout(()=>{
                resolve('商品数据 - 1');
            },1000)
        });

        const p2 = new Promise((resolve, reject)=>{
            setTimeout(()=>{
                // resolve('商品数据 - 2');
                reject('出错啦!');
            },1000)
        });

        //调用 allsettled 方法
        const result = Promise.allSettled([p1, p2]);
        console.log(result);  //返回Promise成功的结果
        
        
        const res = Promise.all([p1, p2]);

        console.log(res);  //根据有情况返回Promise成功或失败的结果

三、String.prototype.matchAll

String.prototype.matchAll() 返回一个包含所有匹配正则表达式(或带有全局标志的字符串)的结果的迭代器(iterator)。这个方法比 String.prototype.match() 方法更加强大,因为它可以处理正则表达式中带有全局标志(g)的情况,并返回一个包含所有匹配信息的迭代器,而不仅仅是匹配结果的数组。

let str = `<ul>
    <li>
        <a>肖生克的救赎</a>
        <p>上映日期: 1994-09-10</p>
    </li>
    <li>
        <a>阿甘正传</a>
        <p>上映日期: 1994-07-06</p>
    </li>
</ul>`;

//声明正则
const reg = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/sg

//调用方法 
const result = str.match(reg);
console.log(result);

const resultAll = str.matchAll(reg);
console.log(resultAll);

for(let v of resultAll){
    console.log(v);
}

const arr = [...resultAll];

console.log(arr);

四、可选链操作符

1、一般情况下的写法(使用&&不存在值但是不报错)

 function main(config){
const dbHost = config && config.db && config.db.host;
console.log(dbHost);
        }

2、不使用&&符号会报错

function main(config){
    const dbHost = config.db.host;
    console.log(dbHost);
}

3、不使用&&符号的时候,怎么保证不报错,运用可选链操作符?.

 function main(config){
    const dbHost = config?.db?.host;
    console.log(dbHost);
}

五、动态 import

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>动态 import </title>
</head>
<body>
    <button id="btn">点击</button>
    <script src="./js/app.js" type="module"></script>
</body>
</html>
export function hello(){
    alert('Hello');
}
// import * as m1 from "./hello.js";
//获取元素
const btn = document.getElementById('btn');

btn.onclick = function(){
import('./hello.js').then(module => {
    module.hello();
});
}

六、BigInt

更大的数值

//大整形
let a = 521n;
console.log(a, typeof(a));

//函数
let n = 123;
console.log(BigInt(n));
console.log(BigInt(1.2));

//大数值运算
let max = Number.MAX_SAFE_INTEGER;
console.log(max);
console.log(max + 1);
console.log(max + 2);

console.log(BigInt(max))
console.log(BigInt(max) + BigInt(1))
console.log(BigInt(max) + BigInt(2))

七、globalThis

globalThis:全局的this,始终指向全的this

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>globalThis</title>
</head>
<body>
    <script>
        console.log(globalThis);
    </script>
</body>
</html>
console.log(globalThis);