ES2020新特性

[TOC]

Dynamic import

不同于 ECMAScript2015 中的静态引入模块,Dynamic import 提供了按需引入计算模块名称脚本内部执行,并返回一个promise

const modulePage = 'page.js';
import(modulePage)
.then((module) => {
module.default();
});
(async () => {
const helpersModule = 'helpers.js';
const module = await import(helpersModule)
const total = module.sum(2, 2);
})();

Promise.allSettled()

promise中有两个重要的方法:promise.all()promise.race(),新增的 promise.allSettled() 方法,返回一个在所有给定的promise都已经fulfilledrejected后的promise,并带有一个对象数组,每个对象表示对应的promise结果。

用法

Promise.allSettled(iterable);
  • 参数

    iterable: 一个可迭代的对象,所有成员都是 promise

  • 返回值

    只要所有的 promise 都已经完成,无论是 resolve 还是 reject ,所有返回的 promise 都会集中为 一个数组, 数组包含每一个 promise 执行的结果。

    每一个结果都是一个对象,包含一个 status 字符串,值为 fulfilled 或者 rejected,此外,还包含一个 fulfilled 时的 value或者 rejected 时的 reson

    const promise1 = Promise.resolve(3);
    const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'foo'));
    const promises = [promise1, promise2];

    Promise.allSettled(promises).
    then((results) => results.forEach((result) => console.log(result)));

    // Object { status: "fulfilled", value: 3 }
    // Object { status: "rejected", reason: "foo" }

浏览器兼容性

image-20201010112650897

String.prototype.matchAll(RegExp)

以往,当我们使用 String.prototype.match() 方法时,总是返回一个数组,其中包含所有完全匹配的字符串:

const text = "From 2019.01.29 to 2019.01.30";
const regexp = /(?<year>\d{4}).(?<month>\d{2}).(?<day>\d{2})/gu;
const results = text.match(regexp);

console.log(results);
// [ '2019.01.29', '2019.01.30' ]

matchAll() 还能够返回所有 Regex 捕获组:

const text = "From 2019.01.29 to 2019.01.30";
const regexp = /(?<year>\d{4}).(?<month>\d{2}).(?<day>\d{2})/gu;
const results = Array.from(text.matchAll(regexp));

console.log(results);
// [
// [
// '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' }
// ]
// ]

可选链操作符(?.)

访问属性

当要访问嵌套在对象内部的属性时,我们很有可能会遇到这样的错误:

Uncaught TypeError: Cannot read property...

所以, 当我们需要访问一个属性时,我们经常会这样写以避免错误:

let foo = obj && obj.foo.// 确认 obj 和 obj.foo 都不是 undefined 或 null

但是即使是这样写也会经常遗漏,且繁琐,如果采用可选链式调用,就可以大量简化这样的前置校验:

let foo = obj ?. foo
let bar = obj ?. foo ?. bar

有了可选链操作符(?.),在访问 obj.foo.bar 之前,不再需要明确地校验 obj.foo 的状态,一旦遇到 null 或者 undefined就会返回 undefined

访问方法

当我们需要尝试调用一个可能不存在的方法时,可以使用可选链来避免返回异常:

let result = obj.someMethod?.();
//  ES2019的写法
function doSomething(onContent, onError) {
try {
// ... do something with the data
}
catch (err) {
if (onError) { // 校验onError是否真的存在
onError(err.message);
}
}
}
// 使用可选链进行函数调用
function doSomething(onContent, onError) {
try {
// ... do something with the data
}
catch (err) {
onError?.(err.message); // 如果onError是undefined也不会有异常
}
}

可选链和表达式

使用方括号和属性名的形式来访问属性:

let foo = obj?.['prop' + 'Name'];

访问数组元素:

let item = arr ?. [20];

可选链不能用于赋值

let object = {};
object?.property = 1; // Uncaught SyntaxError: Invalid left-hand side in assignment

浏览器兼容性

image-20201009183538356

空值合并操作符( ?? )

通常,当我们需要为判断变量是否为 null ,并为变量赋值时,我们需要利用 逻辑或操作符(||),当左边为假值时返回右侧操作数:

let foo;
// foo is never assigned any value so it is still undefined
let someDummyText = foo || 'Hello!';

// output: 'Hello!'

看上去并没有什么问题,但 || 是一个布尔逻辑运算符,左侧的操作数会被强制转换为布尔值,因此,所有的假值(0, ‘’, NaN, null, undefined)都会被转为 false:

let count = 0;
let text = "";

let number = count || 42;
let message = text || "hi!";
console.log(number); // 42,而不是 0
console.log(message); // "hi!",而不是 ""

而使用空值合并操作符可以避免,只有在第一个操作数为 null 或者 undefined 时,才返回第二个操作数:

let count = 0;
let text = "";

let number = count ?? 42;
let message = text ?? "hi!";
console.log(number); // 0
console.log(message); // “”

与可选链式操作符之间的关系

空值合并操作符针对 undefinednull 这两个值,可选链式操作符(?.) 也是如此。在这访问属性可能为 undefinednull 的对象时,可选链式操作符非常有用。

let foo = { someFooProp: "hi" };

console.log(foo.someFooProp?.toUpperCase()); // "HI"
console.log(foo.someBarProp?.toUpperCase()); // undefined