解讀ES2020(ES11)新特性

簡(jiǎn)介

2015年6月正式發(fā)布ES6小泉,也稱為ES2015寿桨,此后的每一年都會(huì)進(jìn)行部分內(nèi)容進(jìn)行修訂并在6月發(fā)布對(duì)應(yīng)年號(hào)的ES版本始鱼,比如ES2016~ES2020济欢。ES2020是ECMAScript語(yǔ)言規(guī)范的第11版,也被稱為es11忆植。

ES2020特性(參考鏈接)

鏈合并運(yùn)算符

鏈?zhǔn)脚袛噙\(yùn)算符

參考鏈接

如果讀取對(duì)象內(nèi)部的某個(gè)屬性放可,往往需要判斷一下該對(duì)象是否存在,比如獲取list.info.base.userName的值

// 錯(cuò)誤寫法朝刊,當(dāng)某一層級(jí)值為null或undefined時(shí)耀里,會(huì)報(bào)錯(cuò)
const userName = list.info.base.userName;
// 正確寫法(我們常用的方式)
const userName = (list && list.info && list.info.base && list.info.base.userName) || 'userName';

要取的userName處于對(duì)象的第三層,需要三層&&判斷才能取到值拾氓。
es2020引入鏈合并運(yùn)算符冯挎,簡(jiǎn)化上面的寫法。

const userName = list?.info?.base?.userName || 'userName';

鏈合并運(yùn)算符咙鞍,在調(diào)用的時(shí)候判斷左側(cè)的對(duì)象是否為null或undefined织堂。如果是的叠艳,就不再往下運(yùn)算,而是返回undefined易阳。
三種用法:

  • obj?.prop // 對(duì)象屬性
  • obj?.[expr] // 同上
  • func?.(...args) // 函數(shù)或?qū)ο蠓椒ǖ恼{(diào)用
    示例代碼
// obj?.prop
let list = {
  info: {
    // base: {
    //     userName: 'eyunhua'
    // }
  }
}
const userName = list?.info?.base?.userName || 'userName'; // 判斷?.左側(cè)表達(dá)式是否為null或undefined附较,否,則繼續(xù)往下運(yùn)算
// func?.(...args)
funtion register(a, b) {
    console.log(a, b, 'register function');
}
this.register?.(1, 2); // register函數(shù)存在潦俺,則執(zhí)行此函數(shù)拒课,并且可傳參
// obj?.\[expr\]
let hex = "#C0FFEE".match(/#([A-Z]+)/i)?.[0];
console.log(hex);

Babel插件轉(zhuǎn)換

https://babeljs.io/docs/en/babel-plugin-syntax-optional-chaining

Null判斷運(yùn)算符

屬性值為null或undefined時(shí),指定默認(rèn)值

參考鏈接

讀取對(duì)象屬性的時(shí)候事示,如果某個(gè)屬性的值是null或undefined早像,有時(shí)候需要為它們指定默認(rèn)值。常見(jiàn)做法是通過(guò)||運(yùn)算符指定默認(rèn)值肖爵。

const userName = (list && list.info && list.info.base && list.info.base.userName) || 'userName';

||或運(yùn)算符表達(dá)的意思是左側(cè)表達(dá)式為null卢鹦、undefined''劝堪、false冀自、0,右側(cè)表達(dá)式都會(huì)生效秒啦。但我們想要的只是在nullundefined的時(shí)候生效熬粗。

es2020引入了新的Null判斷運(yùn)算符??。它的行為類似||余境,但是只有運(yùn)算符左側(cè)的值為nullundefined時(shí)驻呐,才會(huì)返回右側(cè)的值。

與鏈判斷運(yùn)算符?.配合使用芳来。

const userName = list?.info?.base?.userName ?? 'userName';

可用于函數(shù)參數(shù)默認(rèn)值的判斷

register(a, b) {
  b = b ?? 3;
}

&&含末、||運(yùn)算符一起使用時(shí),需要用括號(hào)來(lái)表明優(yōu)先級(jí)即舌,要不會(huì)報(bào)錯(cuò)答渔。優(yōu)先執(zhí)行括號(hào)括起來(lái)的部分

// 錯(cuò)誤
a && b ?? c
// 正確
(a && b) ?? c

這個(gè)運(yùn)算符的一個(gè)目的,就是跟鏈判斷運(yùn)算符?.配合使用侥涵,為nullundefined的值設(shè)置默認(rèn)值。

Babel插件轉(zhuǎn)換

https://babeljs.io/docs/en/babel-plugin-proposal-nullish-coalescing-operator

import()

一種使用動(dòng)態(tài)說(shuō)明符異步導(dǎo)入模塊的語(yǔ)法

參考鏈接

import命令會(huì)被 JavaScript 引擎靜態(tài)分析宋雏,先于模塊內(nèi)的其他語(yǔ)句執(zhí)行芜飘。引擎處理import語(yǔ)句是在編譯時(shí),而不是運(yùn)行時(shí)磨总。也就是說(shuō)importexport命令只能在模塊的頂層嗦明,而不能在代碼塊中。

假如我們要實(shí)現(xiàn)根據(jù)判斷引入模塊蚪燕,import命令是不可能實(shí)現(xiàn)的娶牌。

// 報(bào)錯(cuò)
if (page === 'home') {
  import Home from './home';
}

ES2020提案引入import()函數(shù)奔浅,支持動(dòng)態(tài)加載模塊

import(specifier) // specifier為加載模塊的位置或者腳本文件地址

import()函數(shù)返回一個(gè)Promise對(duì)象,加載模塊成功以后诗良,這個(gè)模塊會(huì)作為一個(gè)對(duì)象汹桦,當(dāng)作then回調(diào)的參數(shù)。因此鉴裹,可以使用對(duì)象解構(gòu)賦值的語(yǔ)法舞骆,獲取輸出接口。

import(`./home.js`)  // home.js中export const export1 = ''; ....
  .then(({export1, export2})=> 
    // 加載成功的回調(diào)
  })
  .catch(err => {
    // 加載失敗的回調(diào)
  });

import()是運(yùn)行時(shí)執(zhí)行径荔,也就是說(shuō)督禽,什么時(shí)候運(yùn)行到這一句,就會(huì)加載指定的模塊总处。另外狈惫,import()函數(shù)與所加載的模塊沒(méi)有靜態(tài)連接關(guān)系,這點(diǎn)也是與import語(yǔ)句不相同鹦马。import()類似于Noderequire方法胧谈,區(qū)別主要是前者是異步加載,后者是同步加載菠红。

適用場(chǎng)合

  1. 按需加載(比如點(diǎn)擊時(shí)加載某個(gè)文件或者模塊)
  2. 條件加載(比如if判斷模塊中)
  3. 動(dòng)態(tài)的模塊路徑(比如模塊路徑是實(shí)時(shí)生成)

Babel插件轉(zhuǎn)換

https://babeljs.io/docs/en/babel-plugin-syntax-dynamic-import

export * as ns from 'module'

在模塊內(nèi)使用的專用語(yǔ)法

參考鏈接

在一個(gè)模塊內(nèi)第岖,先輸入模塊再輸出模塊, import語(yǔ)句可與export語(yǔ)句寫在一起试溯。
注意:
寫在一行后蔑滓,實(shí)際上并沒(méi)有導(dǎo)入接口,只是對(duì)接口進(jìn)行了轉(zhuǎn)發(fā)遇绞,導(dǎo)致在當(dāng)前模塊不能使用此接口键袱。

export { foo, bar } from 'my_module';

// 可以簡(jiǎn)單理解為
import { foo, bar } from 'my_module';
export { foo, bar };

es2020之前有一種import復(fù)合寫法:

import * as someIdentifier from "someModule";

es2020引入對(duì)應(yīng)的export寫法:

export * as someIdentifier from "someModule";
// 等同于
import * as ns from "mod";
export {ns};

更多import和export介紹

Babel插件轉(zhuǎn)換

安裝插件@babel/plugin-proposal-export-namespace-from

npm install --save-dev @babel/plugin-proposal-export-namespace-from

在babel.cofig.js中添加plugin

{
  "plugins": ["@babel/plugin-proposal-export-namespace-from"]
}

參考鏈接:

  1. https://github.com/tc39/proposal-export-ns-from
  2. https://babeljs.io/docs/en/babel-plugin-proposal-export-namespace-from

BigInt

一個(gè)用于處理任意精度整數(shù)的新數(shù)字基元

參考鏈接

JavaScript 所有數(shù)字都保存成 64 位浮點(diǎn)數(shù),這給數(shù)值的表示帶來(lái)了兩大限制摹闽。

  1. 數(shù)值的精度:只能到 53 個(gè)二進(jìn)制位(相當(dāng)于 16 個(gè)十進(jìn)制位)蹄咖,大于這個(gè)范圍的整數(shù),JavaScript 是無(wú)法精確表示的付鹿。
  2. 大于或等于2的1024次方的數(shù)值澜汤,JavaScript 無(wú)法表示,會(huì)返回Infinity舵匾。
// 超過(guò) 53 個(gè)二進(jìn)制位的數(shù)值俊抵,無(wú)法保持精度
Math.pow(2, 53) === Math.pow(2, 53) + 1 // true

// 超過(guò) 2 的 1024 次方的數(shù)值,無(wú)法表示
Math.pow(2, 1024) // Infinity

關(guān)于js中最大的安全整數(shù)為什么是2的53次方減1坐梯?

為了更精確地表示沒(méi)有位數(shù)限制的整數(shù)徽诲,ES2020引入了不同于Number數(shù)字類型的BigInt數(shù)字類型, 只用來(lái)表示整數(shù)(大整數(shù)),沒(méi)有位數(shù)的限制谎替,任何位數(shù)的整數(shù)都可以精確表示偷溺。為了與 Number 類型區(qū)別,BigInt 類型的數(shù)據(jù)必須添加后綴n钱贯。

const a = 2172141653n;
const b = 15346349309n;

// BigInt 可以保持精度
a * b // 33334444555566667777n

// 普通整數(shù)無(wú)法保持精度
Number(a) * Number(b) // 33334444555566670000

typeof運(yùn)算符對(duì)于BigInt數(shù)據(jù)類型挫掏,返回bigint

typeof 1n // bigint

Bigint對(duì)象
參考鏈接

JavaScript 原生提供BigInt對(duì)象,可以用作構(gòu)造函數(shù)生成 BigInt 類型的數(shù)值喷舀。轉(zhuǎn)換規(guī)則基本與Number()一致砍濒,將其他類型的值轉(zhuǎn)為 BigInt。

BigInt(123) // 123n
BigInt('123') // 123n
BigInt(false) // 0n
BigInt(true) // 1n

繼承的方法

// 繼承自其他對(duì)象的方法
BigInt.prototype.toString()
BigInt.prototype.valueOf()
BigInt.prototype.toLocaleString()

新增方法
BigInt.asUintN(width, BigInt): 給定的 BigInt 轉(zhuǎn)為 0 到 2width - 1 之間對(duì)應(yīng)的值硫麻。
BigInt.asIntN(width, BigInt):給定的 BigInt 轉(zhuǎn)為 -2width - 1 到 2width - 1 - 1 之間對(duì)應(yīng)的值爸邢。
BigInt.parseInt(string[, radix]):近似于Number.parseInt(),將一個(gè)字符串轉(zhuǎn)換成指定進(jìn)制的 BigInt拿愧。

轉(zhuǎn)換運(yùn)算
參考鏈接

數(shù)學(xué)運(yùn)算
參考鏈接

其他運(yùn)算
參考鏈接

作為vue props使用---暫不支持

已經(jīng)在開(kāi)發(fā)中杠河,PR處于open狀態(tài)

https://github.com/vuejs/vue/pull/11191

Babel插件轉(zhuǎn)換

https://babeljs.io/docs/en/babel-plugin-syntax-bigint

Promise.allSettled

新的Promise組合器不會(huì)短路參考鏈接

該方法由 ES2020 引入。
接受一組 Promise 實(shí)例作為參數(shù)浇辜,包裝成一個(gè)新的 Promise 實(shí)例券敌。只有等到所有這些參數(shù)實(shí)例都返回結(jié)果,不管是fulfilled還是rejected柳洋,包裝實(shí)例才會(huì)結(jié)束待诅,一旦結(jié)束,狀態(tài)總是 fulfilled熊镣,不會(huì)變成rejected卑雁。狀態(tài)變成fulfilled后,Promise 的監(jiān)聽(tīng)函數(shù)接收到的參數(shù)是一個(gè)數(shù)組绪囱,每個(gè)成員對(duì)應(yīng)一個(gè)傳入Promise.allSettled()Promise 實(shí)例测蹲。

const resolved = Promise.resolve(42);
const rejected = Promise.reject(-1);

const allSettledPromise = Promise.allSettled([resolved, rejected]);

allSettledPromise.then(function (results) {
  console.log(results);
});
// [
//    { status: 'fulfilled', value: 42 },
//    { status: 'rejected', reason: -1 }
// ]

監(jiān)聽(tīng)函數(shù)接收到的數(shù)組,每個(gè)成員都是一個(gè)對(duì)象鬼吵,對(duì)應(yīng)傳入Promise.allSettled()的兩個(gè) Promise 實(shí)例扣甲。每個(gè)對(duì)象都有status屬性,該屬性的值只可能是字符串fulfilled或字符串rejected齿椅。fulfilled時(shí)琉挖,對(duì)象有value屬性,rejected時(shí)有reason屬性涣脚,對(duì)應(yīng)兩種狀態(tài)的返回值示辈。

對(duì)比Promise.all

const p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('hello');
    }, 1000);
}).then(result => result)
    .catch(e => e);
const p2 = new Promise((resolve, reject) => {
    throw new Error('報(bào)錯(cuò)了');
}).then(result => result);
    .catch(e => {
        console.log('p2:' + e);
    });
// const p = Promise.allSettled([p1, p2]);
const p = Promise.all([p1, p2]);

p.then(function (results) {
    console.log(results);
}).catch(err => {
    console.log('settled:' + err);
});

對(duì)比Promise.race

const p3 = new Promise((resolve, reject) => {
    // setTimeout(() => {
    resolve('成功了');
    // }, 2000);
});
const race = Promise.race([
    p3,
    new Promise(function (resolve, reject) {
        setTimeout(() => reject(new Error('request timeout')), 1000);
    })
]);

race.then(data => {
    console.log('success:', data);
}).catch(error => {
    console.log('error:', error);
});
相同點(diǎn):

接受一組 Promise 實(shí)例作為參數(shù),包裝成一個(gè)新的 Promise 實(shí)例

不同點(diǎn):
  • 狀態(tài)

Promise.all

  1. p1和p2實(shí)例狀態(tài)都為fulfilled時(shí)涩澡,p的狀態(tài)才會(huì)變成fulfilled,此時(shí)p1、p2的返回值組成一個(gè)數(shù)組妙同,傳遞給p的回調(diào)函數(shù)
  2. 只要p1射富、p2之中有一個(gè)被rejected,p的狀態(tài)就變成rejected粥帚,此時(shí)第一個(gè)被reject的實(shí)例的返回值胰耗,會(huì)傳遞給p的回調(diào)函數(shù)

Promise.allSettled

一旦結(jié)束,狀態(tài)總是fulfilled芒涡,不會(huì)變成rejected(也就是永遠(yuǎn)進(jìn)不到p的catch回調(diào))柴灯。
Promise.race

其中一實(shí)例返回狀態(tài),p的狀態(tài)就會(huì)發(fā)生改變费尽,并且不會(huì)再變

  • 返回值

Promise.all

返回?cái)?shù)組赠群,每一個(gè)成員都是實(shí)例對(duì)應(yīng)的結(jié)果

Promise.allSettled

返回?cái)?shù)組,數(shù)組的每一個(gè)成員都是對(duì)象旱幼,每個(gè)對(duì)象都有status屬性查描,該屬性的值只可能是字符串fulfilled或字符串rejectedfulfilled時(shí)柏卤,對(duì)象有value屬性冬三,rejected時(shí)有reason屬性,對(duì)應(yīng)兩種狀態(tài)的返回值.

Promise.race

每一個(gè)實(shí)例對(duì)應(yīng)的結(jié)果

  • 應(yīng)用場(chǎng)景

Promise.all

參數(shù)Promise實(shí)例中是否有被reject的實(shí)例缘缚,無(wú)法確定所有請(qǐng)求都已結(jié)束

Promise.allSettled

可以確定所有請(qǐng)求都已結(jié)束

Promise.race

只要有返回值勾笆,立馬停止其他請(qǐng)求

String.prototype.matchAll()

返回一個(gè)正則表達(dá)式在當(dāng)前字符串中所有的匹配

參考鏈接:

  1. https://es6.ruanyifeng.com/#docs/regex#String-prototype-matchAll
  2. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/matchAll

ES2020之前

let regex = /t(e)(st(\d?))/g;
let string = 'test1test2test3';

let matches = [];
let match;
while (match = regex.exec(string)) {
  matches.push(match);
}
console.log(matches); // 返回正則表達(dá)式在當(dāng)前字符串所有匹配(數(shù)組)

ES2020新增matchAll新特性

可一次性取出所有匹配,但是返回的是一個(gè)遍歷器(Iterator)桥滨,而非數(shù)組窝爪。可以用for of循環(huán)取出该园。
相對(duì)于返回?cái)?shù)組酸舍,返回遍歷器的好處在于,如果遍歷結(jié)果是一個(gè)很大的數(shù)組里初,那么遍歷器比較節(jié)省資源啃勉。
遍歷器轉(zhuǎn)換成數(shù)組,也是比較方便双妨,可以使用...運(yùn)算符和Array.from()就可以了淮阐。

let regex = /t(e)(st(\d?))/g;
let string = 'test1test2test3';
[...string.matchAll(regex)];
或
Array.from(string.matchAll(regex));

globalThis

一種在不同環(huán)境中獲取頂層對(duì)象的通用方式參考鏈接

不同環(huán)境中獲取全局對(duì)象的方法不同

  • 瀏覽器里面,頂層對(duì)象是window刁品,但 Node 和 Web Worker 沒(méi)有window泣特。
  • 瀏覽器和 Web Worker 里面,self也指向頂層對(duì)象挑随,但是 Node 沒(méi)有self状您。
  • Node 里面,頂層對(duì)象是global,但其他環(huán)境都不支持

為了實(shí)現(xiàn)在不同環(huán)境中取到頂層對(duì)象膏孟,可采用下面三元表達(dá)式的方法實(shí)現(xiàn)眯分。

// 方法一
(typeof window !== 'undefined'
   ? window
   : (typeof process === 'object' &&
      typeof require === 'function' &&
      typeof global === 'object')
     ? global
     : 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');
};

但這種方式相對(duì)比較麻煩、復(fù)雜柒桑。es2020引入globalThis作為頂層弊决,在任何環(huán)境下都存在。

image.png

參考鏈接:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末魁淳,一起剝皮案震驚了整個(gè)濱河市飘诗,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌界逛,老刑警劉巖昆稿,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異仇奶,居然都是意外死亡貌嫡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門该溯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)岛抄,“玉大人,你說(shuō)我怎么就攤上這事狈茉》蛲郑” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵氯庆,是天一觀的道長(zhǎng)蹭秋。 經(jīng)常有香客問(wèn)我,道長(zhǎng)堤撵,這世上最難降的妖魔是什么仁讨? 我笑而不...
    開(kāi)封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮实昨,結(jié)果婚禮上洞豁,老公的妹妹穿的比我還像新娘。我一直安慰自己荒给,他們只是感情好丈挟,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著志电,像睡著了一般曙咽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上挑辆,一...
    開(kāi)封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天例朱,我揣著相機(jī)與錄音孝情,去河邊找鬼。 笑死洒嗤,一個(gè)胖子當(dāng)著我的面吹牛咧叭,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播烁竭,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼吉挣!你這毒婦竟也來(lái)了派撕?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤睬魂,失蹤者是張志新(化名)和其女友劉穎终吼,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體氯哮,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡际跪,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了喉钢。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片姆打。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖肠虽,靈堂內(nèi)的尸體忽然破棺而出幔戏,到底是詐尸還是另有隱情,我是刑警寧澤税课,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布闲延,位于F島的核電站,受9級(jí)特大地震影響韩玩,放射性物質(zhì)發(fā)生泄漏垒玲。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一找颓、第九天 我趴在偏房一處隱蔽的房頂上張望合愈。 院中可真熱鬧,春花似錦叮雳、人聲如沸想暗。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)说莫。三九已至,卻和暖如春寞焙,著一層夾襖步出監(jiān)牢的瞬間储狭,已是汗流浹背互婿。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留辽狈,地道東北人慈参。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像刮萌,于是被迫代替她去往敵國(guó)和親驮配。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355