种草ES2020超级好用的新特性

253 阅读5分钟

前言

ES6(ES2015)大家已经用了很久,ES2020 是 ECMAScript 对应 2020 年的版本。
这个版本不像 ES6 那样包含了大批量的新特性。但也添加了很多实用方便的特性。
接下来一起看下这些简单有用的新特性吧~

1. 可选链操作符(Optional Chaining)

可选链操作符 可以让我们在查询多个层级的对象时,不需要再进行各种冗余的前置校验

日常开发中,我们经常遇到需要访问在对象内部嵌套了好几层的属性,一旦有某个层级的对象找不到的时候,就会遇到下图这样的错误:

于是你需要这样修改你的代码,使得你的代码的健壮性更强

let num = obj && obj.first && obj.first.second;

在访问 obj.first.second 之前要确认 obj 和 obj.first 的值非 null 且不是 undefined。 有了可选链式调用,可以大量简化类似繁琐的前置校验操作,可以改成如下方式:

let num = obj?.first?.second;

如果obj或obj.first是null/undefined,表达式将会短路计算直接返回undefined

浏览器的支持情况

2. 空位合并操作符(Nullish coalescing Operator)

我们在工作中经常会遇到一种情况,当某个值不存在的时候会给一个默认的值,我们经常会采用下面的方式:

let c = a || b

这种方式有个明显的弊端,他会覆盖所有的假值,比如 0、''、false、null、undefined 等,这些值在某些情况下可能是有效的数据。比如下面的情况:


let person = {
  info: {
    name: '小乔',
    age: '18',
    num: 0
  }
}
console.log(person.info.num || 1) //1

上面的示例中,num 属性的值为 0,却被等同于假值。 为了解决这个问题,ES2020 诞生了一个新特性 —— 空位合并操作符,用 ?? 表示,如果表达式在 ?? 左侧的运算符求值为 undefined 或者 null,就返回其右侧的默认值。可以看下以下的案例:

const x = null;
const y = x ?? 500;
console.log(y); // 500
const n = 0
const m = n ?? 9000;
console.log(m) // 0

浏览器的支持情况

3. Promise.allSettled

我们知道 Promise.all 具有并发执行异步任务的能力。但它最大的问题就是 如果参数中的任何一个 promise 为reject 的话,整个 Promise.all 调用会立即停止,并返回一个 reject 的新的 Promise 对象。看下面的例子:


const promiseList = [
 Promise.resolve(1),
 Promise.resolve(2),
 Promise.reject('error')
];

Promise.all(promiseList)
 .then(responses => console.log(responses))
 .catch(e => console.log(e))    // "error"
 

假如有这样的场景:一个页面有三个区域,分别对应三个独立的接口数据,使用 Promise.all 来并发请求三个接口,如果其中任意一个接口出现异常,状态是 reject,这会导致页面中这三个区域的数据全部都无法展示出来,这个结果是我们无法接受的。Promise.allSettled 的出现就可以解决这个痛点:


Promise.allSettled([
  Promise.reject({ code: 500, msg: '服务异常' }),
  Promise.resolve({ code: 200, list: [] }),
  Promise.resolve({ code: 200, list: [] })
]).then(res => {
  console.log(res)
})

看一下它的返回结果:

Promise.allSettledPromise.all 类似, 其参数接受一个Promise的数组, 返回一个新的Promise, 唯一的不同在于, 它不会进行短路, 也就是说当Promise全部处理完成后,我们可以拿到每个Promise的状态, 而不管是否处理成功

浏览器的支持情况

4. String.prototype.matchAll

使用方式:给定一个字符串和一个正则表达式,.matchAll()为所有匹配的匹配对象返回一个迭代器。

const matchIterator = str.matchAll(regExp);

如果一个正则表达式在字符串里面有多个匹配,现在一般使用 /g 修饰符,在循环中逐一取出:

function collectGroup1 (regExp, str) {
  const matches = []
  while (true) {
    const match = regExp.exec(str)
    if (match === null) break
    matches.push(match[1])
  }
  return matches
}
console.log(collectGroup1(/"([^"]*)"/g, `"foo" and "bar" and "baz"`))
// [ 'foo', 'bar', 'baz' ]

值得注意的是,如果没有修饰符 /g,exec() 只返回第一个匹配,现在通过 String.prototype.matchAll 方法,可以一次性取出所有匹配


function collectGroup1 (regExp, str) {
  let results = []
  for (const match of str.matchAll(regExp)) {
    results.push(match[1])
  }
  return results
}
console.log(collectGroup1(/"([^"]*)"/g, `"foo" and "bar" and "baz"`))
// ["foo", "bar", "baz"]

浏览器的支持情况:

5. Dynamic import

现在前端打包资源越来越大,前端应用初始化时根本不需要全部加载这些逻辑资源,为了首屏加载速度更快,很多时候都是动态导入(按需加载)模块,这样可以提供应用程序的性能。 其中按需加载这些逻辑资源一般都会在某一个事件回调中去执行:


el.onclick = () => {
  import('/modules/my-module.js')
    .then(module => {
      // Do something with the module.
    })
    .catch(err => {
      // load error;
    })
}

import()可以用于script脚本中,import(module) 函数可以在任何地方调用。它返回一个解析为模块对象的 promise。 这种方式也支持 await 关键字:

let module = await import('/modules/my-module.js');

浏览器的支持情况:

6. globalThis

globalThis 是一个全新的标准方法,用来获取全局的 对象。之前我们一般会通过如下的一些方法获取:

  • 全局变量 window
    是一个经典的获取全局对象的方法。但是它在 Node.js 和 Web Workers 中并不能使用
  • 全局变量 self
    通常只在 Web Workers 和浏览器中生效。但是它不支持 Node.js。一些人会通过判断 self 是否存在识别代码是否运行在 Web Workers 和浏览器中
  • 全局变量 global
    只在 Node.js 中生效

如果我们想写一套通用的代码来获取全局对象,一般会封装一个如下的函数:

const 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');
}

globalThis 目的就是提供一种标准化方式访问全局对象,有了 globalThis 后,你可以在任意上下文,任意时刻都能获取到全局对象。

如果您在浏览器上,globalThis将为window,如果您在Node上,globalThis则将为global。因此,不再需要考虑不同的环境问题。

// worker.js
globalThis === self
// node.js
globalThis === global
// browser.js
globalThis === window

新提案也规定了,Object.prototype 必须在全局对象的原型链中。下面的代码在最新浏览器中已经会返回 true 了:

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

浏览器的支持情况


参考文章

  • TC39 Proposals
  • MDN文档
  • 5 ECMAScript Proposals To Look Out For In ES2020
  • ES2020 Features in simple examples