ECMAScript 2020 新特性

ECMAScript 2020 新特性

最近看 ECMAScript Finish 阶段新增了不少 ES11 的新特性,趁着这段时间业务不忙了解一下。

String.prototype.matchAll

介绍 matchAll() 前,先来看看 match()

1
2
3
4
5
6
const phoneString = `
021-23678790
0797-2336903
0791-2573891
`;
const phoneReg = /(\d{3,4})-(\d{6,})/g;

看结果,是可以正常匹配到所有匹配项,但却没办法匹配到子项(group)。如果想要匹配子项,那么需要把全局匹配 /g 标识去掉。matchAll() 返回 RegExpStringIterator 对象。

1
2
const phoneReg = /(\d{3,4})-(\d{6,})/;
console.log(phoneString.match(phoneReg));

如果既想要匹配所有匹配项,又想要匹配子项,那么 match() 是无法满足的。ES11 提供了 matchAll()

import()

目前前端项目打包的资源越来越大,但应用初始化时资源并不需要全量加载,为了提高页面性能,往往需要按需加载资源。

ES11 中通过 import() 在某些业务逻辑中动态的加载页面资源,如:回调函数里。

1
2
3
4
5
6
7
el.addEventListener('click', (e) => {
e.preventDefault();

import(*.js)
.then(module => {}) // 加载成功
.catch(err => {}); // 加载异常
})

import() 返回一个包含模块对象的 Promise,当然也支持 await

1
const module = await import(url);

import.meta

通过 import.meta 对象可以获取模块相关的信息,如: url

1
2
3
4
5
// index.html
<script src="./index.mjs" type="module"></script>

// index.mjs
console.info(import.meta.url);

BigInt

JavaScript 中 Number 类型都保存为 64 位浮点数,精确度只能到 53 位,且无法正确表示大于或等于 2^1024 的数值。

1
2
3
4
Math.pow(2, 53) === Math.pow(2, 53) + 0.1; // true

Math.pow(2, 1023); // 8.98846567431158e+307
Math.pow(2, 1024); // Infinity

为了解决上诉问题,ES11 中引入了新的数据类型 BigInt,用于表示任意位数的整数

1
2
3
4
5
6
7
8
const num = 123n;

typeof num; // 'bigint'

// 进制表示
0b1101n; // 二进制
0o777n; // 八进制
0xFFn; // 十六进制

Promise.allSettled

在处理异步并发任务时,有时候我们并不关心异步操作的结果,只关心所有异步任务是否完成,目前 Promise.all() 无法实现这个功能。

Promise 在 ES11 中新增了 Promise.allSettled() ,该方法接收一组 Promise 实例为参数,返回一个新的实例。只有所有 Promise 参数实例都有返回结果,Promise.allSettled() 返回的实例状态才会发生变化。

1
2
3
4
5
6
const settledPromise = Promise.allSettled([Promise.resolve(1), Promise.reject(-1)]);
settledPromise.then(result => console.info(result));
// [
// { status: 'fulfilled', value: 1 },
// { status: 'rejected', reason: -1 }
// ]

GlobalThis

JavaScript 在不同运行环境中获取全局对象的方式都不一样,在浏览器中可以通过 windowthis 等方式获取,在 Web Worker 中通过 self 来获取,在 Node 中通过 global 获取。为了方便及统一,ES11 提供了一种标准化的方式来获取全局对象:globalThis

1
globalThis.document.location;
1
2
3
Object.getPrototypeOf(globalThis); // Window

Window.prototype.isPrototypeOf(globalThis); // true

For-in mechanics

在 [ECMA-262 3rd Edition](http://www.ecma-international.org/publications/files/ECMA-ST-ARCH/ECMA-262, 3rd edition, December 1999.pdf) 中定义 for-in 属性遍历的顺序是由按对象定义时属性的书写顺序决定,但在 ECMA-262 5rd Edition 中对遍历机制又进行了调整,并未并且规定具体的规则,不同浏览器有不同的实现,这导致对属性的遍历顺序存在不一致的问题。ES11 中要求对象的遍历实现上,各浏览器要保持一致。

目前,for-in 的遍历顺序是先按升序遍历整数属性(不包括类似 +1-2 一类),其他属性按正常的定义顺序遍历

Optional Chaining

通常在获取多层级对象的属性值时,需要对各层级的属性进行校验

1
const city = person && person.address && person.address.city;

不进行校验的话,很容易出现 TypeError

对此,ES11 进行了优化,可以通过 ?. 来简化校验。

?. 操作符与 . 类似,两者的区别在于,?. 在获取对象属性时,如果其引用对象为 null 或 undefined,则表达式会发生短路,直接返回 undefined。

1
2
person?.address?.city; // undefined
person?.address?.city ?? '上海市'; // '上海市'

Nullish coalescing Operator

在 JavaScript 中我们通常会按下面的方式给某个变量或对象属性设置默认值

1
2
3
4
5
const name = user.name || '默认名称';

const name = user.name ? user.name : '默认名称';
const name = [null, undefined].includes(user.name) ? '默认名称' : user.name;
const name = user.name ?? '默认名称';

img

ES11 新增了更简洁的空值合并操作符(??),左侧值为 nullundefined 时返回右侧默认值

但对于逻辑或操作符来说,''0 都会转化为 false,容易产生逻辑错误。在业务上,大多是是想判断变量是否为 undefined 或者 null

参考