ES2020

BigInt

面试官问你: js的基本数据类型有几种?

你自信的答: 6种

一般这样答没问题。但是,严格来说,现在的js有7种数据类型。es2020新加了bigint类型

以往,Js 中 Number类型只能安全的表示-(2^53-1)至 2^53-1 的值,超过这个范围将丢失精度。

如果后台定义字段数据类型时,定了个INT(64),并且确实有那么大的数的话,普通的number就不好使了。

现在,我们可以定义bigint类型表示超大数

// 1. 在整数字面量后面加n
var bigIntNum = 9007199254740993n;

// 2. 使用 BigInt()
var bigIntNum = BigInt(9007199254740);

空值运算符 (??)

很多时候,我们想根据这个值是否为空来做接下来的操作。例如

const a = age || 123;

但是, 我们通常希望0也被算作age

此时 大部分人这样做

const age = 0;
const a = age || 123;
console.log(a); // 123
// 因为!0 = true,所以输出了123

const b = typeof age !== "undefined" ? age : 123; 
console.log(b); // 0

但是这样不美观,而且只能判断undefined。其实,有一个冷门运算符??可以判断undefined和null,这样是比较符合普遍需求的。

const age = 0;
const a = age ?? 123;
console.log(a); // 0

可选链式操作符(?.)

跟上面的类似,这个操作符也很有用。
举个例子:

const foo = { name: "zengbo" };

let a = foo.name.toUpperCase(); // "ZENGBO"
let b = foo.name.firstName.toUpperCase(); // 报错!

很多时候,我们不知道对象是否有这个属性,并且判断多个层级的对象时,需要进行冗余的各种前置校验,所以可能会这样做:

const foo = { name: "zengbo" };

let a;
if (foo.name && foo.name.firstName) 
    a = foo.name.firstName.toUpperCase();
else a = "zhao";

但是这样还是不美观。es2020有了可选链式操作符?.

这是当对象上没有这个键的时候,不会报错,而是赋值undefined

const foo = { name: "zengbo" };

let a = foo.name?.toUpperCase(); // "ZENGBO"
let b = foo.name?.firstName?.toUpperCase(); // "undefined"

配合刚刚讲到的?? ,我们可以这样做

let a = foo.name?.firstName?.toUpperCase() ?? "zhao" // "ZENGBO"

Promise.allSettled

Promise.all 缺陷

我们都知道 Promise.all可以并发执行异步任务。但它的最大问题就是如果其中某个任务出现异常(reject),所有任务都会挂掉,直接进入reject 状态。

想象场景:页面有三个区域,分别对应三个独立的接口数据,使用 Promise.all来并发三个接口,如果其中任意一个接口服务异常,这会导致页面中三个区域数据全都无法渲染出来, 很明显,这是不合理的,如下:

Promise.all([
    Promise.reject({code: 500, msg: '服务异常'}),
    Promise.resolve({ code: 200, list: []}),
    Promise.resolve({code: 200, list: []})
])
.then((ret) => {
   ...
})
.catch((error) => {
    // 本例中会执行到这个回调
})

es2020的Promise.allSettled就是解决这样的问题,无论什么状态都会进入then,然后我们在并发任务的 then 里面通过 filter来过滤出想要的业务逻辑结果,这就能最大限度的保障业务当前状态的可访问性,不至于某个接口挂了导致在整个页面挂了。

Promise.allSettled([
    Promise.reject({code: 500, msg: '服务异常'}),
    Promise.resolve({ code: 200, list: []}),
    Promise.resolve({code: 200, list: []})
])
.then((ret) => {
    const result = ret.filter((item) => {
        return el.status !== 'rejected';
    });
});

dynamic-import

以往,我们要在头部全量导入资源。
现在可以动态导入资源并且回调了, 按需加载使用,nice!

import(`/path/source.js`)
    .then((module) => {
        module.doSomthing();
    }).catch((err) => {
        // load error;
    })

globalThis

js 在不同的环境获取全局对象有不同方式,node 中通过 global, web中通过 window, self 等,有些甚至通过 this 获取。所以,过去获取全局对象,需要这样:

var getGlobal = function () { 
  if (typeof self !== 'undefined') { return self; } 
  if (typeof window !== 'undefined') { return window; } 
  if (typeof global !== 'undefined') { return global; } 
  throw new Error('unable to locate global object'); 
}; 

var globals = getGlobal();

es2020后,我们可以通过globalThis直接获取全局对象,方便快捷且规范

globalThis.setTimeout ? 
    setTimeout(foo, 100) :
    console.log("此环境没有setTimeout");