「这是我参与2022首次更文挑战的第33天,活动详情查看:2022首次更文挑战」
概况
由于每年都有新语法的发布,ES的版本号都会随之递增,关于ES版本的取名根据发布的年份来定,但是ES6也算是一个泛指,表示ES5后的下一代标准
发布年份 | 缩写昵称 |
---|---|
2016 | ES2016、ES7 |
2017 | ES2017、ES8 |
2018 | ES2018、ES9 |
2019 | ES2020、ES10 |
2020 | ES2020、ES11 |
2021 | ES2021、ES12 |
使用新特性时,若项目babel不支持编译,可以安装相应的babel插件。更多配置可以查看babel插件列表,或者直接引入@babel/preset-env,基本包含所有的新特性(babel7以上)
ES7(ES2016)
Array.prototype.includes()
之前有find,findIndex,indexOf方法用来寻找对象或者数组中的值和索引,一个是为了在语义上清晰的描述这个场景,一个是为了判断NaN。
[1, 2, NaN].includes(NaN);// true
[1, 2, NaN].includes(3,1);// false
幂运算符
let cubed = 2 ** 3;
// 相当于2 * 2 * 2 Math.Pow(2,3)
ES8(ES2017)
Object.values/Object.entries
只返回对象自身所有可遍历的值,查看当前是否可遍历 可以通过getOwnPropertyDescriptors获取
obj = {
a: 1,
b: 2
}
Object.values(obj) //[1,2]
Object.entries(obj) //[['a',1],['b',2]]
Object.getOwnPropertyDescriptors()
获取当前对象的数据属性
value
— 属性实际的值writable
— 属性的值是否可以被修改get
— 获取函数,在读取属性时调用set
— 设置函数,在写入属性时调用configurable
— 属性是否可以通过 delete 删除并重新定义,是否可以修改它的特 性,以及是否可以把它改为访问器属性enumerable-是否可枚举
let obj = {
a: 1
}
Object.getOwnPropertyDescriptors(obj)
// {
// a: {
// value: 1,
// configurable: true,
// enumerable: true,
// writable: true
// }
// }
由于Object.assign不能拷贝get
属性和set
属性,可以通过Object.create和getOwnPropertyDescriptors实现对象的拷贝。
const obj = {
set c(v) {
console.log('设置c')
c = v;
},
};
newObj = Object.assign({}, obj);
newObj.c = 1 //
newObj1 = Object.create({}, Object.getOwnPropertyDescriptors(obj))
newObj.c = 1 //设置c
String padding(目标长度,添加字符)
计算时分秒,为了规范成hh:mm:ss,可以选用下边的方法
"3".padStart(2, "00"); // '03'
"x".padEnd(5, "ab"); // 'xabab'
异步函数 async/await
generator
函数的语法糖,可以以同步写法实现异步的操作,async
函数返回一个 Promise
对象,内部return
语句返回的值,会成为then
方法回调函数的参数
generator函数需要手动去调用next方法获取值,async会自动执行next,最终输出一个promise。
function fakeRequest() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("请求成功");
}, 2000);
});
}
async function getData() {
console.log("start");
const res = await fakeRequest();
console.log(res);
console.log("end");
}
getData();
//start
//请求成功
//end
ES9(ES2018)
扩展运算符
通常用来进行一些数据的分裂或者合并
let obj={a:1}
let res={
...obj,
b:2
}
Promise.prototype.finally
常见的场景是
- 关闭数据请求时的
laoding
状态 - 不管前面的操作成功或是失败,最后都要执行一个指定的回调函数操作
Promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
异步遍历器 for await...of
使用for.. of
遍历异步操作时,使用await
进行顺序执行。
使用for await...of
,for...of的实现逻辑
循环自动调用这个对象,执行这个异步的操作得到一个 Promise 对象后。await
用来处理这个 Promise
对象,拿到结果,再把得到的值(item
)传入for...of
的循环体。
function Gen(time) {
return new Promise((resolve, reject) => {
setTimeout(function () {
resolve(time)
}, time)
})
}
async function test() {
console.log('开始', Date.now())
let arr = [Gen(2000), Gen(5000), Gen(8000)]
for await (let i of arr) {
console.log(Date.now(), await i);
}
console.log('结束', Date.now())
}
test()
// 开始 1645690296443
// 1645690296443 2000
// 1645690298444 5000
// 1645690301446 8000
// 结束 1645690304449
正则表达式
dotAll模式
.可以匹配大部分字符,除了一些特殊的比如换行符\n、回车符\r、还有一些分隔符,为了匹配所有的字符增加一个 s/dotAll 标志。
而且还引入了一个dotAll
属性,返回一个布尔值,表示该正则表达式是否处在dotAll
模式。
'ee.\ne'.match(/.+/g) //['ee.','e']
'ee.\ne'.match(/.+/s) //['ee.↵e']
let reg=/.+/s
reg.dotAll //true
具名匹配
?<>
将每组匹配出来的结果指定一个名字,获取group
直接得到匹配的结果。
const reg = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
console.log(reg.exec('2020-02-01'))
const groups = reg.exec('2020-02-01').groups
const {year, month, day} = groups
console.log(year, month, day)//2020 02 01
后行断言(?<=y)x
“先行断言”指的是,x
只有在y
前面才匹配,必须写成/x(?=y)/
“先行否定断言”指的是,x
只有不在y
前面才匹配,必须写成/x(?!y)/
'100%11'.match(/\d+(?=%)/g) // ['100'] 先行断言,只匹配百分号之前的数字
'44e33r'.match(/\d+(?!%)/g)//['44','33'] 先行否定断言
'3$11e2'.match(/(?<=\$)\d+/g) // ['11'] 后行断言,只匹配在$后边的数字
'3$1ee2'.match(/(?<!\$)\d+/g) //['3','2'] 后行否定断言
ES10(ES2019)
Object.fromEntries()
Object.entries 的逆向操作,接受一个二维数组或者 Map(),返回一个对象。多用于转换Map().
const map = new Map();
map.set('name', 'taotao');
map.set('age', '25');
Object.fromEntries(map);
//{
// name: 'taotao',
// age: 25
// }
Object.fromEntries([
['name', 'taotao'],
['age', 25]
]);
//{
// name: 'taotao',
// age: 25
// }
trimStart()、trimEnd()
对 str.trim()的补全。
' input'.trimStart(); // input
'input '.trimEnd(); // input
flat()
抹平数组
const arr = [1,2,3,[4,5,6,[7,8,9]]];
arr.flat(); // [1,2,3,4,5,6,[7,8,9]] // 默认深度1
arr.flat(1); // [1,2,3,4,5,6,[7,8,9]] // 深度 = 维度 - 1
arr.flat(2); // [1,2,3,4,5,6,7,8,9] // 深度 = 维度 - 1
arr.flat(Infinity); // [1,2,3,4,5,6,7,8,9] // Infinity -> 打成一维数组
flatMap()
flatMap()
方法首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。它与 map 连着深度值为1的 flat 几乎相同。
const arr1 = [1, 2, 3, 4];
arr1.map(x => [x * 2]);
// [[2], [4], [6], [8]]
arr1.flatMap(x => [x * 2]);
// [2, 4, 6, 8]
// only one level is flattened
arr1.flatMap(x => [[x * 2]]);
// [[2], [4], [6], [8]]
Symbol.description
获取 Symbol 的描述字符串
const syb = Symbol('taotao');
console.log(syb.description); // taotao
ES11(ES2020)
Promise.allSettled()
把全部的异步操作结果都返回回来。
(async () => {
const res = await Promise.allSettled([
new Promise((resolve, reject) => {
setTimeout(() => {
resolve(5000);
}, 5000);
}),
new Promise((resolve, reject) => {
setTimeout(() => {
reject(2000);
}, 2000);
}),
]);
console.log(res);
})()
// [
// {
// "status": "fulfilled",
// "value": 5000
// },
// {
// "status": "rejected",
// "reason": 2000
// }
// ]
class 的私有变量
私有变量 #
必须以 #
访问
class Person {
// 公有属性
name;
// 私有属性
#age;
#weight;
constructor(name, age, weight) {
this.name = name;
this.#age = age;
this.#weight = weight;
}
log() {
console.log(this.name);
console.log(this.#age);
console.log(this.#weight);
}
}
const girl = new Person('2B', 150, '280kg');
console.log(girl);
girl.age = 18; // 新增属性
girl.#age = 18; // 报错
matchAll
一般用于爬虫抓取文案之类
const str =
'<ul>' +
'<li>' +
'<a>肖生克的救赎</a>' +
'<p>上映日期:1994-09-1</p>' +
'</li>' +
'<li>' +
'<a>阿甘正传</a>' +
'<p>上映日期:1994-07-6</p>' +
'</li>' +
'<\/ul>'
const reg = /<li>.*?<a>(.*?)<\/a>(.*?)<p>(.*?)<\/p>/sg
//调用方法
const result = str.matchAll(reg);
for (let v of result) {
console.log(v);
}
可选链
ts
的可选链被 js
原生的支持了。
const person = {
a: {
b: 'bb',
c: 'cc'
}
}
const a1 = person && person.a && person.a.b;
const b1 = person?.a?.b;
BigInt
新的基础数据类型
正常的js只能表达 -(2^53 - 1)
到 2^53 - 1
之间的数值(包含边界值)
let a = BigInt(1);
let b = BigInt(1.2);// 报错
let number = Number.MAX_SAFE_INTEGER; // 9007199254740991
let numberAdd1 = number + 1; // 9007199254740992
let numberAdd2 = number + 2; // 9007199254740992
let numberAdd3 = number + 3; // 9007199254740992
let bigIntNumberAdd1 = BigInt(number) + 1; // 报错
let bigIntNumberAdd2 = BigInt(number) + BigInt(2); // 9007199254740993n
??
ts
的 ??
被 js
原生的支持了,除了 null
和 undefined
之外都是真。
let user = {
u1: 0,
u2: false,
u3: null,
u4: undefined,
u5: '',
}
let u1 = user.u1 ?? 'a1' // 0
let u2 = user.u2 ?? 'a2' // false
let u3 = user.u3 ?? 'a3' // a3
let u4 = user.u4 ?? 'a4' // a4
let u5 = user.u5 ?? 'a5' // ''
ES12(ES2021)
||=、&&=、??=
let a = 1;
let b = 2;
b ||= a; // b = b || a
b &&= a; // b = b && a
b ??= a; // b = b ?? a
数字分隔符 _
const number = 1_000_000_000; // 一亿
const phone = 138_1234_1234; // 号码
const test1 = 138__1234_1234; // 报错
const test2 = _138_1234_1234; // 变量名
replaceAll
到了校验的作用,确保替换所有
let str = 'abc aef ah';
str.replace(/a/g, '*');
str.replaceAll('a', '*');
str.replaceAll(/a/, '*'); // 报错 -> 必须加 g
Promise.any()
返回第一个成功的异步操作结果。
(async () => {
const res = await Promise.any([
new Promise((resolve, reject) => {
setTimeout(() => {
resolve(5000);
}, 5000);
}),
new Promise((resolve, reject) => {
setTimeout(() => {
reject(2000);
}, 2000);
}),
]);
console.log(res); // 5000
})();
返回第一个完成的异步操作结果。
(async () => {
const res = await Promise.race([
new Promise((resolve, reject) => {
setTimeout(() => {
resolve(5000);
}, 5000);
}),
new Promise((resolve, reject) => {
setTimeout(() => {
reject(2000);
}, 2000);
}),
]);
console.log(res); // 报错
})();
垃圾回收 FinalizationRegistry
const registry = new FinalizationRegistry((value) => {
console.log('变量被回收了:', value)
})
(() => {
const a = {a:123}
registry.register(a,12)
})();
本地化 Intl
是ECMAScript国际化API的命名空间,它提供对语言敏感的字符串比较、支持数字格式化以及日期和时间的格式化。
const date = new Date();
const str = new Intl.DateTimeFormat('zh').format(date); // 2022/02/28