书接上回
五、ES10(es2019)
(1)Array.prototype.flat()
es10为数组扁平化提供了两个api,通过参数控制扁平深度(默认深度为 1),话不多说直接上代码
const arr1 = [1, 2, [3, 4]];
arr1.flat(); // [1, 2, 3, 4]
const arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat(); // [1, 2, 3, 4, [5, 6]]
const arr3 = [1, 2, [3, 4, [5, 6]]];
arr3.flat(2); // [1, 2, 3, 4, 5, 6]
const arr4 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]];
arr4.flat(Infinity); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
语法点评:有了它,就不用再自己封装扁平化方法了。
(2)Array.prototype.flatMap()
const arr = [1, 2, 3, 4];
arr.flatMap(x => [x * 2]); // [2, 4, 6, 8]
// 只有一层是扁平的
arr.flatMap(x => [[x * 2]]); // [[2], [4], [6], [8]]
语法点评:扁平化的扩展功能。
(3)Object.fromEntries()
它接收一个键值对列表(Map实例),并返回一个真实对象,其属性由条目给出。
它的功能与 Object.entries() 正相反。
const entries = new Map([
["apple", "origin"],
["grapes", "peach"]
]);
console.log(Object.fromEntries(entries));
// { apple: "origin", grapes: "peach" }
使用场景1:交换属性和值
function foo(obj) {
return Object.fromEntries(Object.entries(obj)
.map(([key, value]) => [value, key])
)
}
console.table({ name: "oli", age: "12" })
console.table(foo({ name: "oli", age: "12" }))
使用场景2:将 url上的参数提取为一个对象
const params = Object.fromEntries(new URLSearchParams("foo=bar&baz=qux"));
console.log(params); // {foo: "bar", baz: "qux"}
语法点评:被低估的一个api,其实可以帮我们简化处理一些场景。
(4)String.prototype.trimStart() 和 String.prototype.trimEnd()
修整字符串前后的空格
let message = " Hello ";
message = message.trimEnd().trimStart();
console.log(message); // "Hello"
语法点评:搜索时,可以检测用户是不是只搜索了空格。
(5)try catch升级
catch的参数有时候是多余的,现在可以省略
try {
const data = JSON.parse(obj)
return true
} catch {
return false
}
语法点评:很好,又为我们码农减了一点点负。
六、ES11(es2020)
(1)动态 import
通过import声明引用的所有模块(包括初始化暂时用不到的模块)都会在初始化阶段前置加载,影响首屏性能。
import()能够在函数、分支等非顶层作用域使用,按需加载、懒加载都不是问题。
例子:路由懒加载
import { lazy } from "react";
const route = [
{
title: "博客",
path: "/home",
component: lazy(() => import("@/views/Home")),
},
{
title: "文章",
path: "/article",
search:"?category=all",
component: lazy(() => import("@/views/Article")),
},
{
path: "/article/:id",
component: lazy(() => import("@/views/Article/ArticleDetail")),
}
]
语法点评:性能优化新的突破。
(2)可选链-更详细的了解,请点击[https://blog.csdn.net/Ght19970126/article/details/122084892]
平时我们访问对象第n级的时候,可能某一级的节点并不存在,导致js程序崩溃。除非提前用if或者&&预判。
可选链操作符(?.) 通过用户检测不确定的中间节点,如果不存在中间节点则返回undefined。
//一个对象
const user = {
info:{
age: 11
}
}
//要取值:
console.log(user.info.age) // 11
//当无法判断user对象中是否有info的属性,info属性下面是否有age属性我们会:
console.log(user&&user.info&&user.info.age)
//而有了?. 可选链运算符之后 可以如此
console.log(user?.info?.age)
语法点评:减负神技。
(3)Promise.allSettled
常规的promise.all并发多个实例只要有一个失败,就会停止执行并跳入catch方法。
而这个Promise.allSettled不管多个实例成功还是失败,一定会执行完,并将结果收集到一个数组中。
Promise.all([
new Promise.reject("a1"),
new Promise.resolve("a2")
]).then((ret) => {
// 不会执行
console.log(ret)
}).catch((error) => {
// 因为有一个promise返回为reject。所以程序只会走到这里
// 输出:a1
console.log(error)
})
// 使用es11的Promise.allSettled
Promise.allSettled([
new Promise.reject("a1"),
new Promise.resolve("a2")
]).then((ret) => {
// 输出
// 0: {status: "fulfilled", value: "a1"},
// 1: {status: "rejected", value: "a2"}
console.log(ret)
// 这样可以过滤掉rejected,避免整段程序运行错乱
handleFun(ret.filter(el => el.status !== "rejected"))
})
语法点评:在需要执行多个的异步操作并收集所有结果时非常有效,即使某些异步操作可能失败。
(4)BigInt(第7个基本类型)
BigInt是一种特殊的数字类型,它支持任意长度的整数。
先说说它诞生的意义:
JS 中的Number类型只能安全地表示-9007199254740991 (-(2^53-1)) 和9007199254740991(2^53-1)之间的整数,任何超出此范围的整数值都可能失去精度。
// 注意最后一位的数字
29007199254740992 === 9007199254740993; //true
要创建一个 bigint,可以在一个整数的末尾添加字符n,或者调用函数 BigInt()。BigInt 函数使用字符串、数字等来创建一个BigInt。
19007199254740992n === 9007199254740993n; //false
语法点评:如果你需要用到这么大的数字,那它就派上用场了。
(5)全局this
全局this。在浏览器中它是 window, 在 Node.js 中它是global。
语法点评:好像除了在全局作用域快速拿到window,就没啥用了。
(6)String.protype.matchAll()
原有的 match() 方法仅返回完整的匹配结果,却不会返回特定正则表达式组。而 matchAll()返回的迭代器不仅包括精确的匹配结果,还有全部的正则模式捕获结果
var str = "From 2019.01.29 to 2019.01.30";
var allMatchs = str.matchAll(/(?<year>d{4}).(?<month>d{2}).(?<day>d{2})/g);
for (const match of allMatchs) {
console.log(match);
}
// [
// [
// "2019.01.29",
// "2019",
// "01",
// "29",
// index: 5,
// input: "From 2019.01.29 to 2019.01.30",
// groups: [Object: null prototype] { year: "2019", month: "01", day: "29" }
// ],
// [
// "2019.01.30",
// "2019",
// "01",
// "30",
// index: 19,
// input: "From 2019.01.29 to 2019.01.30",
// groups: [Object: null prototype] { year: "2019", month: "01", day: "30" }
// ]
// ]
语法点评:正则家族又强大了,某些场景可能会很有用。
七、ES12(es2021)
(1)replaceAll
字符串新的原型方法(String.prototype.replaceAll)
有了它,以后【替换所有】就不用写正则了
const str = "today is work will be finished today";
//old
//const newStr = str.replace(/today/g, "tomorrow");
//new
const newStr = str.replaceAll("today", "tomorrow");
(2)Promise.any()
返回第一个 fullfilled 的 promise ,若全部 reject,则返回一个带有失败原因的 AggregateError
(3)数字分隔符
数字分隔符是数字之间添加的下划线;当代码解析时,下划线会被自动去除;
let n1 = 1_000_000_000;
console.log(n1); // This will print: 1000000000
语法点评:写很大的数字可以更容易读。
(4)三个逻辑赋值
+||= 逻辑或赋值,等同于:a || (a = b)
&&= 逻辑与赋值,等同于:a && (a = b)
??= 逻辑合并赋值,等同于:a ?? (a = b)
举栗子:
//当左边为false时赋值
let myPlaylist = {songsCount: 0, songs:[]};
myPlaylist.songsCount ||= 100;
console.log(myPlaylist); // This will print: {songsCount: 100, songs: Array(0)}
//当左边为true时赋值
let myFiles = {filesCount: 100, files:[]};
myFiles.filesCount &&= 5;
console.log(myFiles); // This will print: {filesCount: 5, files: Array(0)}
//当左边为null或者undefined时赋值
let userDetails = {firstname: "Katina", age: 24}
userDetails.lastname ??= "Dawson";
console.log(userDetails); // This will print: {firstname: "Katina", age: 24, lastname: "Dawson"}
点评:运用这哥仨,我们的代码逼格又高了。
八、ES13(es2022)
(1)at()
根据传入的数字获取字符串、数组的元素。不同于[]的是它还可以获取负数,也就是倒数
// 1.数组
const arr = [10, 20, 30, 40];
console.log(arr.at(0)); // 10
// at方法也支持负值
console.log(arr.at(-1)); // 40
// 2.字符串
const message = "Hello";
console.log(message.at(0)); // H
console.log(message.at(-1)); // o
(2)全局await
现在在全局作用域下,可以直接使用await
function setTimeoutAsync(timeout) {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, timeout);
});
}
// Waits for timeout - no error thrown
await setTimeoutAsync(3000);
语法点评:不建议这么用,可能会阻塞js进程导致变慢。
(3)类允许在constructor外部声明字段
class Car {
color = "blue";
age = 2;
}
const car = new Car();
console.log(car.color); // blue
console.log(car.age); // 2
等同于
class Car {
constructor() {
this.color = "blue";
this.age = 2;
}
}
const car = new Car();
console.log(car.color); // blue
console.log(car.age); // 2
语法点评:在类不需要接收参数,或者不需要调用super关键字时,就可以免写constructor了,且少写一些this 。
(4)类的私有方法和字段
现在可以将私有字段和成员添加到类中,方法是在其前面加上井号 (#),试图从类外部访问它们会导致错误
class Person {
#firstName = "Joseph";
#lastName = "Stevens";
get name() {
return `${this.#firstName} ${this.#lastName}`;
}
}
const person = new Person();
console.log(person.name);//Joseph Stevens
console.log(person.#firstName);
console.log(person.#lastName);
// SyntaxError: Private field "#firstName" must be
// declared in an enclosing class
语法点评:如果你需要私藏类的变量,那就派上用场了。
(5)类静态块
ES13 允许在创建类时定义只执行一次的静态块,这类似于其他支持面向对象编程的语言(如 C# 和 Java)中的静态构造函数。
一个类的类主体中可以有任意数量的静态 {} 初始化块,它们将与任何交错的静态字段初始值设定项一起按照声明的顺序执行,我们可以在静态块中使用超属性来访问超类的属性。
class Vehicle {
static defaultColor = "blue";
}
class Car extends Vehicle {
static colors = [];
static {
this.colors.push(super.defaultColor, "red");
}
static {
this.colors.push("green");
}
}
console.log(Car.colors); // [ "blue", "red", "green" ]
(6)in 运算符
来检查一个对象中是否有一个特定的私有字段,使用 in 运算符
class Car {
#color;
hasColor() {
return #color in this;
}
}
class House {
#color;
hasColor() {
return #color in this;
}
}
const car = new Car();
const house = new House();
console.log(car.hasColor()); // true;
console.log(car.hasColor.call(house)); // false
console.log(house.hasColor()); // true
console.log(house.hasColor.call(car)); // false
(7)Object.hasOwn()
用来检测对象中是否含有指定属性,它接受对象和属性作为参数,返回 true/false。
const obj = { name: "hyl", color: "red" };
console.log(Object.hasOwn(obj, "color")); // true
console.log(Object.hasOwn(obj, "name")); // false
function userAction() {
try {
apiCallThatCanThrow();
} catch (err) {
throw new Error("New error message", { cause: err });
}
}
try {
userAction();
} catch (err) {
console.log(err);
console.log(`Cause by: ${err.cause}`);
}
(8)高级捕获错误
错误对象现在有一个 cause 属性,用于指定导致即将抛出的错误的原始错误。这有助于为错误添加额外的上下文信息并帮助诊断意外行为,我们可以通过在作为第二个参数传递给 Error() 构造函数的对象上设置 cause 属性来指定错误的原因。
function userAction() {
try {
apiCallThatCanThrow();
} catch (err) {
throw new Error("New error message", { cause: err });
}
}
try {
userAction();
} catch (err) {
console.log(`Cause by: ${err.cause}`);
}
//Cause by: ReferenceError: apiCallThatCanThrow is not defined
(9)Array.prototype.findLast()和Array.prototype.findLastIndex()
快速查找到符合条件的最后一项或者下标。与find正相反
const nums = [7, 14, 3, 8, 10, 9];
const lastEven = nums.findLast((num) => num % 2 === 0);
const lastEvenIndex = nums.findLastIndex((num) => num % 2 === 0);
console.log(lastEven); // 10
console.log(lastEvenIndex); // 4