2020年4月2日,TC39确定了ES2020的新特性,虽然现在还是 candidate 阶段,需要等到 Ecma GA 的最后确认。按照惯例每年3月份在TC39委员会上,Stage 4的特性会被确定,新的语法特性已被认可;也就是说,因为Stage 4的特性都是确定会作为新版特性发布的,所以基本上在每年3月份的时候,当前年度版本的新特性已经确定下来了。4月份-7月份为ECMA CC、ECMA GA复审阶段,7月份ECMA General Assembly批准新的标准,即在7月份当年份标准正式发布。
V8打标签的新特性如下:
1.Dynamic import()
原生支持动态引入JavaScript文件,不需要借助Webpack和Babel,此特性可以实现按需加载就像现在的 code splittinig 功能。可以在 if-else 语句里面引入代码。
Dynamic import() 返回的是 promise 所以和 async/await 配合使用:
// math.js
const add = (num1, num2) => num1 + num2;
export { add };
// index.js
const doMath = async (num1, num2) => {
if (num1 && num2) {
const math = await import('./math.js');
console.log(math.add(5, 10));
};
};
doMath(4, 2);
详见:https://v8.dev/features/dynamic-import
2.BigInt
在 BigInt 之前,有最大安全整数:
const max = Number.MAX_SAFE_INTEGER;
// → 9_007_199_254_740_991
当我们加法运算时:
max + 1;
// → 9_007_199_254_740_992
是我们的预期结果,可是当我们加2时:
max + 2;
// → 9_007_199_254_740_992
并不是我们所期望的结果,居然是和加1时结果一样。也就是任何的整数运算如果超过了安全范围(Number.MIN_SAFE_INTEGER to Number.MAX_SAFE_INTEGER),所以为了解决这个问题BigInt就出现了。那如何把一个整数转换为BigInt,两种方法:
1. BigInt(123) 2. 123n
在计算一下上面的问题:
BigInt(Number.MAX_SAFE_INTEGER) + 2n;
// → 9_007_199_254_740_993n
注意:BigInt的值不能和其他的值直接做运算,需要显示类型转换。
一切其它例子:
类型:
typeof 123n;
// → 'bigint'
比较:
42n === BigInt(42);
// → true
42n == 42;
// → true
42n === 42
// → false
if-else
if (0n) {
console.log('if');
} else {
console.log('else');
}
// → logs 'else', because `0n` is falsy.
详见:https://v8.dev/features/bigint
3.Module namespace exports
JavaScript 模块之前就有下面的语法:
import * as utils from './utils.mjs';
可是一直没有对应的导出语法,所以2020加上了:
export * as utils from './utils.mjs';
等同于下面:
import * as utils from './utils.mjs';
export { utils };
详见:https://v8.dev/features/module-namespace-exports
4.String.prototype.matchAll
相比于之前的math提供了更多的信息:
math:
const string = 'Magic hex numbers: DEADBEEF CAFE';
const regex = /\b\p{ASCII_Hex_Digit}+\b/gu;
for (const match of string.match(regex)) {
console.log(match);
}
// Output:
//
// 'DEADBEEF'
// 'CAFE'
matchAll:
const string = 'Magic hex numbers: DEADBEEF CAFE';
const regex = /\b\p{ASCII_Hex_Digit}+\b/gu;
let match;
while (match = regex.exec(string)) {
console.log(match);
}
// Output:
//
// [ 'DEADBEEF', index: 19, input: 'Magic hex numbers: DEADBEEF CAFE' ]
// [ 'CAFE', index: 28, input: 'Magic hex numbers: DEADBEEF CAFE' ]
详见:https://v8.dev/features/string-matchall
5:Promise.allSettled
这个Promise的静态方法类似 jQuery 的 done,只给出 promise 已经结束并需要知道成功、失败。适用的例子就是请求接口结束后,不管成败与否移出 loading 样式:
const promises = [
fetch('/api-call-1'),
fetch('/api-call-2'),
fetch('/api-call-3'),
];
// Imagine some of these requests fail, and some succeed.
await Promise.allSettled(promises);
// All API calls have finished (either failed or succeeded).
removeLoadingIndicator();
详见:https://v8.dev/features/promise-combinators
6.globalThis
若之前你的代码既要在浏览器,也要在Nodejs同时也在 web-workers,获取 global 对象绝对是一件繁琐的事:
// A naive attempt at getting the global `this`. Don’t use this!
const getGlobalThis = () => {
if (typeof globalThis !== 'undefined') return globalThis;
if (typeof self !== 'undefined') return self;
if (typeof window !== 'undefined') return window;
if (typeof global !== 'undefined') return global;
// Note: this might still return the wrong result!
if (typeof this !== 'undefined') return this;
throw new Error('Unable to locate global `this`');
};
const theGlobalThis = getGlobalThis();
所以ES2020给我带来了globalThis,不论在何种环境下执行代码它都代表全局对象:
global === window // true
global.setTimeout === window.setTimeout // true
详见:https://v8.dev/features/globalthis
7.Optional chaining
在JavaScript中获取嵌套的属性时容易产生错误,同时代码也冗长不易阅读:
// Error prone-version, could throw.
const nameLength = db.user.name.length;
// Less error-prone, but harder to read.
let nameLength;
if (db && db.user && db.user.name)
nameLength = db.user.name.length;
那经过 Optional chaining 来更改一下:
// Still checks for errors and is much more readable.
const nameLength = db?.user?.name?.length;
上面的代码是不是简洁明了,那当db、user、name 是 null 或 undefined 时,nameLength 则会等于 undefined 而不是报错。若可以确定name始终存在且为字符串,则可以改成:
const nameLength = db?.user?.name.length
Optional chaining还有个优势,若 name 是空字符串,之前的写法会 nameLength 会得到 undefined,而新写法会得到 0。
8.Nullish coalescing
ES2020增加了一种新的处理默认值的短路求值特性。再说此属性之前,我们先回忆一下:&& 和 || ,它俩都是用来处理 truthy、falsy值的。在 JavaScript 中,null、undefined、false、0、NaN 和 '' 都代表假值,既然我们已经有&& 和 || 来处理了,那为何还要新增一个 ?? 呢?因为一些场景,它俩并不能优雅的处理:
function Component(props) {
const enable = props.enabled || true;
// …
}
当enabled没有设置时,也就是等于undefined时,我们给一个默认值true。可是当我们给 props.enabled 赋值为 false 时,结果并不是我们所希望的,当然此问题可以通过下面方法更改:
function Component(props) {
const enable = props.enabled !== false;
// …
}
可是此问题还是挺普遍,例如当 '' 和 0 就是期望值的时候,就像上面的 false 一样,所以为了解决此问题,引入了 ?? 特性。
function Component(props) {
const enable = props.enabled ?? true;
// …
}
?? 的左侧只处理 null 或 undefined ,效果和 || 类似:
false ?? true; // => false
0 ?? 1; // => 0
'' ?? 'default'; // => ''
null ?? []; // => []
undefined ?? []; // => []
只有左侧的值为 null 或 undefined 时,才返回它右侧的值。
注意点:document.all 是一个类数组,返回页面上所有的节点但是在和 && 、|| 运算时得到的是 falsy,和 ?? 运算则不同。
document.all || true; // => true
document.all ?? true; // => HTMLAllCollection[]
详见:https://v8.dev/features/nullish-coalescing