web

【学习笔记】ECMAScript2020 新特性

Posted by wml on May 26, 2020

ECMAScript 2020(ES11)新特性,不是所有特性都被现代浏览器支持,故还是需要加入Babel进行编译;新特性兼容性

Optional Chaining 可选链式调用

场景:某些情况下知道值会存在,直接引用会报错,使用可选链式操作符即可避免该错误,使用一个问号和一个点组成

用处: 可用于接口数据返回时判断;

// object
let a = {};
console.log(a.b); // undefiend
console.log(a.b.c); //Uncaught TypeError: Cannot read property 'c' of undefined
//es11
console.log(a.b?.c) // undefiend

//array
let m = [1];
console.log(m[0]); // 1
m = null
console.log(m[0]); // Uncaught TypeError: Cannot read property '0' of null
//es11
console.log(m?.[0]); // undefiend

//function
let x = () => {return 'func'};
console.log(x()); // func
x = null;
console.log(x()); //Uncaught TypeError: x is not a function
// es11
console.log(x?.()); // undefined

Nullish Coalescing 空值合并

场景: 为变量提供回退值,通常使用操作符||,适用于大多数情况,但也有些特殊场景,如变量值为布尔值或数字时,如当前值为0时,使用es11??双问号合并操作符即可检查变量是否未数字或布尔值;

用处: 用于变量回退值为特殊场景下的值,如变量值为布尔值或数字

let a = 1;
let b = a || -1; // 1
a = 0;
b = a || -1 // -1,但此时a是一个正常值范围,只不过为0
// es11
b = a ?? -1 // 0

let x = true;
let y = x || true; // true
x = false;
y = x || true; // true,但此时x只是一个为false的布尔值
// es11
y = x ?? true; // false

Private Fields 私有字段

场景: 在别的oo语言早就有类的语法,且可以定义类的公有(public)、私有(private)和受保护(protected)属性,但是在javasctipt中,es6才支持类的语法,es11开始支持私有字段,之前定义私有属性,都是通过加_来伪定义;

用处:es11中可在属性前使用散列符号#来定义私有属性;

class Theme {
  #const_color = 'red';
  constructor(color) {
      this.color = color;
  }
  getColor() {
      return this.#const_color
  }
}

let theme = new Theme('white');
console.log(theme.color); // white
console.log(theme.getColor); // red
//es11,直接调用私有方法报错
console.log(theme.#const_color); // Uncaught SyntaxError: Private field '#const_color' must be declared in an enclosing class

Static Fields 静态字段

场景: 使用类的方法,必须实例化一个类

用处: 使用static字段,类可以被static关键词声明然后从外部调用

class Theme {
  constructor(color) {
      this.color = color;
  }
  getColor() {
      return this.color
  }

  static get_color(color) { // 其实也只是个语法糖而已。。
    return new Theme(color);
  }
}

let theme = new Theme('white');
theme.getColor(); // white
Theme.getColor(); // Uncaught TypeError: Theme.getColor is not a function

Theme.get_color('white'); //Theme {color: "white"}

Top Levek Await 顶级Await

场景: 当前await获取promise结果,需要使用async关键字,全局作用下,只能使用立即调用的函数表达式(IIFE)

用处: 使用顶级Await后,不需要把代码包裹在async函数中

// IIFE
(async () => {
  const result = await fetch(url);
})()

// es11
const Lg = await import(`/i18n/${language}`);
let vue
try {
  vue = await import('vue-url');
}
catch {
  vue = await import('vue-url2);
}

但顶层await也有一些弊端,如:

阻断执行
阻断资源请求
仅限于ES模块,不支持脚本或commonjs模块

Top-level await 臭名昭著的问题;

stage 3 的提案

同级之间可以执行,最终不会阻断; 顶层 await 发生在模块图的执行阶段。至此,所有资源均已获取并链接。没有阻塞获取资源的风险;
顶层 await 仅限于 ES 模块。明确不支持脚本或 CommonJS 模块

Promise.allSettled方法

场景:多个promise请求,可以使用promise.all,但如果其中一个请求失败,则会抛出错误,有些场景下可能希望及时一个请求失败,其他结果能正常返回;

用处: 使用ES11 Promise.allSettled方法,成功会返回一个包含status和vaule的对象,失败则会返回一个status和reason的对象

let promise1 = Promise.resolve('hello');
let promise2 = new Promise((resolve, reject) => setTimeout(reject, 200, 'problem'));

Promise.all([promise1, promise2]).then(([res1, res2]) => {
  console.log(res1, res2)
}); //Promise {<rejected>: "problem"}

// es11
Promise.allSettled([promise1, promise2]).then(([res1, res2]) => {
  console.log(res1, res2)
}); // {status: "fulfilled", value: "hello"} {status: "rejected", reason: "problem"}

Dynamic Import 动态导入

import('/xx/xx.js').then(res => res.method());

使用普遍的webpack已经支持模块打包器来进行代码的转义和优化;

matchAll 匹配所有项

let regexp = /t(e)(st(\d?))/g;
let str = 'test1test2';

let array = [...str.matchAll(regexp)];
console.log(array); 
//["test1", "e", "st1", "1", index: 0, input: "test1test2", groups: undefined], ["test2", "e", "st2", "2", index: 5, input: "test1test2", groups: undefined]

globalThis 全局对象

Javascript可以在浏览器或nodejs中运行,浏览器中的全局对象是window, nodejs中是global,为了统一,es11中引入globalThis;

// 浏览器
window == globalThis // true

// node.js
global == globalThis // true

BigInt

js能够表达的最大数字时2^53-1, BigInt可以创建更大的数字

const evenBiggerNumber = BigInt(9007199254740991);