ES7-11新特性

ES7-ES11新特性

ES7

Array.prototype.includes()

1
2
3
4
const mingzhu = ['西游记', '红楼', '水浒','三国'];

console.log(mingzhu.includes('三国')); // true
console.log(mingzhu.includes('金瓶梅')); // false

指数操作符

1
console.log(2**8);          // 256

ES8

async 和 await

async和await两种语法结合可以让异步代码像同步代码一样。

async函数

  • async函数的返回值为promise对象。
  • promise对象的结果由async函数执行的返回值决定
1
2
3
4
5
6
7
async function getData(){
// 返回结果是一个Promise对象
return 'GeekHall';
}

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

1
2
3
4
5
6
7
async function getData(){
// 抛出错误,返回一个失败的Promise
throw new Error('出错了');
}

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

使用Promise

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
async function getData(){
return new Promise((resolve, reject) => {
resolve('成功的数据');
});
}

const result = getData();

// 调用then方法
result.then(value => {
console.log(value);
}, reason => {
console.warn(reason);
});

await表达式

  • await必须写在async函数中
  • await右侧的表达式一般为promise对象
  • await返回的是promise成功的值
  • await的promise失败了,就会抛出异常,需要通过try…catch捕获异常
1
2
3
4
5
6
7
8
9
10
11
12
13
14

// 创建Promise对象
const p = new Promise((resolve, reject) => {
resolve("成功的值!!");
});

// await 要放在async函数中
async function main(){
let result = await p;
console.log(result);
}

// 调用函数
main();

异常情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 创建Promise对象
const p = new Promise((resolve, reject) => {
reject("失败的值!!");
});

// await 要放在async函数中
async function main(){
try{
let result = await p;
console.log(result);
} catch (e){
console.log(e);
}
}

// 调用函数
main();

async和await的结合使用:

下面内容保存为sample.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
const fs = require('fs');

function readFile1(){
return new Promise((resolve, reject) => {
fs.readFile("./resources/file1.md", (err, data) =>{
// 如果失败
if (err) reject(err);

// 如果成功
resolve(data);
})
})
}


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

// 如果成功
resolve(data);
})
})
}

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

// 如果成功
resolve(data);
})
})
}

// 声明一个async函数
async function main(){
let file1 = await readFile1();
let file2 = await readFile2();
let file3 = await readFile3();

console.log(file1.toString());
console.log(file2.toString());
console.log(file3.toString());
}

main();

然后执行:node sample.js ,即可读取三个文件的内容。

使用async和await发送ajax请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

// 发送Ajax请求,返回的结果是Promise对象。
function sendAjax(url){
return new Promise((resolve,reject) => {

// 创建对象
const x = new XMLHttpRequest();

// 初始化
x.open('GET', url);

// 发送
x.send();

// 事件绑定
x.onreadystatechange = function(){
if (x.readyState === 4){
if (x.status >= 200 && x.status < 300) {
// 成功
resolve(x.response);
} else {
// 失败
reject(x.status);
}
}
}
});
}

// promise then 方法测试
// sendAjax("https://api.apiopen.top/getJoke").then(value => {
// console.log(value);
// }, reason => {
// console.warn(reason);
// });


// async 与 await 方法测试 以后使用axios
// 推荐的做法是axios发请求,await接结果。
async function main (){
// 发送ajax请求
let result = await sendAjax("https://api.apiopen.top/getJoke");
console.log(result);
}
main();

对象展开

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

1
2
3
4
5
6
7
8
9
10
11
12
13
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: '123456'
})

上面的操作在ES9中可以写成下面这种方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
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: '123456',
type: 'master'
})

对象的展开和合并

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 对象的展开和合并:
const skillOne = {
q: '天音破'
}

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

const skillThree = {
e: '天雷破'
}

const skillFour = {
r: '神龙摆尾'
}

const mengseng = {...skillOne, ...skillTwo, ...skillThree, ...skillFour};
console.log(mengseng);

正则表达式扩展

1
2
3
4
5
6
7
8
let str = '<a href="http://www.geekhall.cn">极客堂</a>';

const reg = /<a href="(.*)>(.*)<\/a>/;

const result = reg.exec(str);
console.log(result);
console.log(result[1]); // http://www.geekhall.cn
console.log(result[2]); // 极客堂

使用分组:

1
2
3
4
5
6
const reg1 = /<a href="(?<url>.*)">(?<text>.*)<\/a>/;

const result1 = reg1.exec(str);
console.log(result1);
console.log(result1.groups.url); // http://www.geekhall.cn
console.log(result1.groups.text); // 极客堂

正则扩展 - 反向断言

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 正向断言
let str2 = 'JS1314极客堂520哈哈哈哈哈';
const reg2 = /\d+(?=哈)/;
const result2 = reg2.exec(str2);
console.log(result2);
console.log(result2[0]); // 520

// 不加断言
const reg3 = /\d+/;
const result3 = reg3.exec(str2);
console.log(result3);
console.log(result3[0]); // 1314


// 反向断言
const reg4 = /(?<=堂)\d+/;
const result4 = reg4.exec(str2);
console.log(result4);
console.log(result4[0]); // 520

ES10 Object.fromEntries

ES8中 Object.entries的反操作,可以将二维数组转化为对象。

1
2
3
4
5
6
7
8
9
10
11
const arr = Object.fromEntries([
['name', '极客堂'],
['xueke', ' Java, Python, Php']
]);

// Map
const m = new Map();
m.set('name', 'GeekHall');
const result5 = Object.fromEntries(m);

console.log(result5);

ES10 trimStart,trimEnd

用来清除字符串左侧空白或者右侧空白

ES10 flat与flatMap

flat可以将多维数组转化为低维数组

1
2
3
const arr = [1,2,3,4,[5,6]];
// flat的参数为深度
console.log(arr.flat(2)); // [1,2,3,4,5,6]

flatMap
Map结果维度降低

1
2
3
4
const arr = [1,2,3,4]
const result = arr.map(item => [item*10]); // 返回一个二维数组 [[10],[20],[30],[40]]
const resultFlat = arr.flatMap(item => [item*10]); // 返回一个一维数组 [10,20,30,40]
console.log(result);

ES10 Symbol.prototype.description

1
2
let s = Symbol('极客堂');
console.log(s.description); // 极客堂

私有属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Girl{
// 公有属性
name;

// 私有属性
#age;
#weight;

intro(){
console.log(this.name);
console.log(this.#age);
console.log(this.#weight);
}
constructor(name, age, weight){
this.name = name;
this.#age = age;
this.#weight = weight;
}
}

// 实例化
const g = new Girl('puiyi', 18, '45kg');
console.log(g);
// console.log(g.#weight); // SyntaxError: private field must be declared in an enclosing class.
g.intro(); // 可以正常打印

Promise.allSettled

Promise.allSettled返回一个Promise对象,
无论参数中每个Promise成功与否,返回的Promise对象都是成功的,
并且会返回参数数组中Promise的状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 声明两个Promise对象。
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('商品数据1');
}, 1000)
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('商品数据2');
}, 1000)
});

// 调用allSettled方法
const result = Promise.allSettled([p1, p2]);
console.log(result);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 声明两个Promise对象。
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('商品数据1');
}, 1000)
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("出错啦!");
}, 1000)
});

// 调用allSettled方法
const result = Promise.allSettled([p1, p2]);
console.log(result);

对比Promise.all([p1, p2])

  • Promise.allSettled([p1, p2])返回的是一个Promise,Result里面是Promise数组
  • Promise.all([p1, p2])返回的是一个Promise,Result里面是字符串

当p1和p2中有一个返回reject时:

  • Promise.allSettled([p1, p2])返回的Promise依然是成功的
  • Promise.all([p1, p2])返回的Promise不是成功的

String.prototype.matchAll

使用matchAll进行数据的批量提取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
let str = `<ul>
<li>
<a>云原生Java</a>
<p>出版日期:2015-01-02</p>
</li>
<li>
<a>Spring源码分析</a>
<p>出版日期:2018-11-12</p>
</li>
</ul>`;

// 声明正则
const reg = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/sg
const result = str.matchAll(reg);
console.log(result);

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

1
2
const arr = [...result];
console.log(arr);

可选链操作符

1
2
3
4
5
6
function main(config){
const dbHost = config.db.host;
console.log(dbHost);
}

main()

上面代码由于main方法没有传入参数,会报错
改成下面这种则不会报错,

1
2
3
4
5
6
function main(config){
const dbHost = config?.db?.host;
console.log(dbHost);
}

main()

可选链操作符(?.)前面的config如果传入了再去获取db;
前面的db如果存在再去获取host

bigint

大整型,普通数值后面加一个n

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//BigInt
let n = 521n;
console.log(n, typeof(n));
// 普通数值可以转换为bigint
console.log(BigInt(n1));

// 非整型数值转换则会报错
console.log(BigInt(0.5));

// 大数值运算
let max = Number.MAX_SAFE_INTEGER;
console.log(max); // 9007199254740991
console.log(max+1); // 9007199254740992
console.log(max+2); // 9007199254740992 (普通int到这里结果就已经不对了)

console.log(BigInt(max)) // 9007199254740991n
console.log(BigInt(max) + BigInt(1)) // 9007199254740992n
console.log(BigInt(max) + BigInt(2)) // 9007199254740993n

globalThis

1
console.log(globalThis)