也就是 ES11, 补充 article


目录

  • Optional Chaining 可选链式调用
  • Nullish Coalescing 空值合并
  • Private Fields 私有字段
  • Static Fields 静态字段
  • Top Level Await 顶级 Await
  • Promise.allSettled 方法
  • Dynamic Import 动态引入
  • MatchAll 匹配所有项
  • globalThis 全局对象
  • BigInt

Optional Chaining 可选链式调用

几乎所有前端开发者都曾经遇到过这样的问题

访问一个对象中不存在的属性下的不存在的属性''
访问一个对象中不存在的属性下的不存在的属性''

但是我们只需要知道存不存在, 而不需要直接报错, 这时候可以使用可选链式调用

1
2
3
console.log(persons.person2?.name); // undefined
console.log(arr?.[1]); // undefined
console.log(fn?.()); // undefined

Nullish Coalescing 空值合并

为变量提供回退值,逻辑操作符 || 还是必须的。它适用于很多情况,但不能应用在一些特殊的场景。例如,初始值是布尔值或数字的情况。举例说明,我们要把数字赋值给一个变量,当变量的初始值不是数字时,就默认其为 666

1
2
const num = 111;
const newNum = num || 666; // newNum = 111

假如 num 是 0 就导致了左边 num 为假, newNum = 666

test''
test''

所以即便 num 是数字 0, 最后 newNum 也是 666; 并不是我们需要的效果, 那么我们可以这么写

1
2
const num = 0;
const newNum = num ?? 666; // 0
test''
test''

Private Fields 私有字段

许多具有 classes 的编程语言允许定义类作为公共的,比如 java, c++,受保护的或私有的属性。Public 属性可以从类的外部或者子类访问,protected 属性只能被子类访问,private 属性只能被类内部访问。JavaScript 从 ES6 开始支持类语法,但直到现在才引入了私有字段。要定义私有属性,必须在其前面加上散列符号#。

1
2
3
4
5
6
7
8
9
10
11
12
13
class Person {
name = "hardy";
#age = 18;
getAge() {
return this.#age;
}
}

const p = new Person();

console.log(p.name); // hardy
console.log(p.getAge()); // 18
// console.log(p.#age) SyntaxError: Private field '#age' must be declared in an enclosing class

console.log(p.#age)会报错是因为从外部访问了 Person 的私有属性 age, 所以 SyntaxError: Private field ‘#age’ must be declared in an enclosing class

Static Fields 静态字段

假如声明了 class Person, 然后试图直接访问没有实例化的 Person 的 getAge 方法

1
2
3
4
5
6
class Person {
getAge() {
return 18;
}
}
// console.log(Person.getAge()) Person.getAge is not a function

用上 static 关键字之后

1
2
3
4
5
6
class Person {
static getAge() {
return 18;
}
}
console.log(Person.getAge()); // 18

由此得到: 类方法可以被 static 关键词声明然后从外部调用。

Top Level Await 顶级 Await

大多数想要采用同步的方式书写异步代码的前端玩家, 说到 await 就会想到 async, 因为如果想要使用 await 函数必须用 async 关键字定义, 就像这样:

1
2
3
const fn = async () => {
const res = await fetch(url);
};

那么在全局作用域中去等待某些结果就可能要使用立即调用的函数表达式(IIFE)

1
2
3
(async () => {
const res = await fetch(url);
})();

但引入了 顶级 Await 后,不需要再把代码包裹在一个 async 函数中了, 而是可以直接这样

1
const res = await fetch(url);

这个特性对于解决模块依赖或当初始源无法使用而需要备用源的时候是非常有用的.比如

1
2
3
4
5
6
let module
try {
module = await import('module url')
} catch () {
module = await import('module url1')
}

Promise.allSettled 方法

等待多个 promise 返回结果时,我们通常使用 Promise.all([p1, p2])。那么保不准有些请求失败之后抛错, 然后我们希望的是某个请求失败不影响其他请求正常返回。针对这种情况 ES11 引入了 Promise.allSettled.

1
2
3
4
5
6
7
8
9
10
11
const p1 = Promise.resolve("hello");
const p2 = Promise.reject("not word");
const p3 = Promise.resolve("i word");

Promise.all([p1, p2, p3]).then((res) => {
console.log(res);
});

// [UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "not word".] {
// code: 'ERR_UNHANDLED_REJECTION'
// }

由普通 Promise.all 改成 Promise.allSettled

1
2
3
4
5
6
7
8
9
Promise.allSettled([p1, p2, p3]).then((res) => {
console.log(res);
});

// [
// { status: 'fulfilled', value: 'hello' },
// { status: 'rejected', reason: 'not word' },
// { status: 'fulfilled', value: 'i word' }
// ]

Dynamic Import 动态引入

你也许在 webpack 的模块绑定中已经使用过动态引入。但对于该特性的原生支持已经到来(尤大的新框架 vite 也是利用了 import 时会跑异步的特性直接加载运行时资源文件, 省略了 compiler 的过程)

1
2
3
4
5
6
7
8
9
// js1.js
export default {
getName () { console.log('hardy) }
}

// js2.js
import('js1.js').then(Person => {
Person.getName()
})

MatchAll 匹配所有项

想要查找字符串中所有正则表达式的匹配项和它们的位置,MatchAll 非常有用。
forEach single match demo….(省略)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
let fruits = "pear, apple, banana, apple, orange, apple";
for (const match of fruits.matchAll(/apple/g)) {
console.log(match);
}

// [
// 'apple',
// index: 6,
// input: 'pear, apple, banana, apple, orange, apple',
// groups: undefined
// ]
// [
// 'apple',
// index: 21,
// input: 'pear, apple, banana, apple, orange, apple',
// groups: undefined
// ]
// [
// 'apple',
// index: 36,
// input: 'pear, apple, banana, apple, orange, apple',
// groups: undefined
// ]

⚠️ 需要注意的是 fruits.matchAll 的正则需要完整匹配也就是 g, 否则就会 TypeError: String.prototype.matchAll called with a non-global RegExp argument

globalThis 全局对象

为了在 node 和 window 中可以找到统一的全局对象

1
2
3
4
5
// window下
window === globalThis; // true

// node环境
global === globalThis;

BigInt

JavaScript 中能够精确表达的最大数字是 2^53 - 1。而 BigInt 可以用来创建更大的数字。

1
2
const theBiggerNumber = 9007199254740991n;
const evenBiggerNumber = BigInt(9007199254740991);