ES11來了,不進來看看嘛
前言
ES2020 (ES11)是 ECMAScript 對應 2020 年的版本。這個版本不像 ES6 (ES2015)那樣包含大量新特性。但也添加了許多有趣且有用的特性。本文以簡單的代碼示例來介紹 ES2020新特性。這樣,你可以很快理解這些新功能,而不需要多么復雜的解釋,好了,廢話不多說我們進入正文?
私有變量
類的主要作用之一是將我們的代碼包含在可重用的模塊中。所以會在許多不同地方使用到同一個類,但是又的類里面的一些屬性,為了安全或者是其他的目的,不想讓其他的類能夠去訪問他,修改他,只能他自己用,對于一些學過c#,java等語言的同學來說是比較好理解的,就是 Private一個訪問修飾符,那么在我們的js當中該怎么辦了,
別擔心,他們有的咱js也有,在ES11中也為我們提供了私有變量,通過在變量或函數(shù)前面添加一個哈希符號#,可以將它們設為私有屬性,只在類內(nèi)部可用。
這是我們普通的一個類
class?Money{
??constructor(money){
????this.money=money;
??}
}
let?RMB=new?Money(999);
RMB.money=999999;//這還了得,怎么可以隨便改錢的金額呢
console.log(RMB.money);//可以通過對象的形式去訪問
由于安全,我們不能讓其他的類來隨便更改我們類里面的屬性的值,我們可以使用 ?私有屬性,是只能在類里面進行訪問
class?Money{
??????#money=0;//聲明這個屬性是私有屬性
??????constructor(money){
????????this.#money=money;
??????}
????}
????let?RMB=new?Money(999);
????//RMB.#money=999999;//Uncaught?SyntaxError:?Private?field?'#money'?must?be?declared?in?an?enclosing?class,
????console.log(RMB.#money);//Uncaught?SyntaxError:?Private?field?'#money'?must?be?declared?in?an?enclosing?class
上面的代碼報錯了,哭唧唧
,拿不到私有屬性的值了,怎么辦??
我需要使用我類里面的錢,怎么獲取
我們可以在類里面寫兩個方法,取數(shù)據(jù),寫入數(shù)據(jù),可以進行修改,但是你不能任意改,必須通過我的方法去改,我們可以看看下面的代碼
class?Money{
??#money=0;//聲明這個屬性是私有屬性
??constructor(money){
????this.#money=money;
??}
??getMoney(){//獲取值
????return?this.#money;
??}
??setMoney(money){//寫入值
????this.#money+=money;
??}
}
let?RMB=new?Money(999);
RMB.setMoney(8848)
console.log(RMB.getMoney());
好了,私有變量(屬性),我們就說到這里了,下面我們來看看空值合并運算符吧!
空值合并運算符
在我們平常的工作中,在取一個對象里面的屬性,如果這個屬性沒有值,我們會這樣給他一個默認值
let?user={
??name:'Symbol盧',
??age:18
}
console.log(user.name,"name")//Symbol盧?name
console.log(user.like,"like")//undefined?"like"
//對象里面沒有這個屬性的時候,他一個默認值
console.log(user.like?||?'寫代碼',"like2")//寫代碼?like2?
//ES2020?的???空值合并操作符
console.log(user.sex??'男',"sex");??//男?sex
??//不存在這個sex屬性,就會走后面的默認值,如果存在這個sex屬性,就不會走后面的默認值
**空值合并運算符(*??*)**是一個邏輯運算符。當左側(cè)操作數(shù)為 null 或 undefined 時,其返回右側(cè)的操作數(shù)。否則返回左側(cè)的操作數(shù)。
??和 || 的區(qū)別是什么呢??
他們兩個最大的區(qū)別就是 ' '和 0,??的左側(cè) 為 ' '或者為 0 的時候,依然會返回左側(cè)的值;
|| 會對左側(cè)的數(shù)據(jù)進行boolean類型轉(zhuǎn)換,所以' '和 0 會被轉(zhuǎn)換成false,返回右側(cè)的值
可選鏈操作符
減少訪問深層對象時判斷屬性存不存在的問題。
const?a?=?{};
console.log(a.b.c);?//?這里會報Err,?無法從undefined中得到c
console.log(person?.profile?.name);?//?""
console.log(person?.hobby?.work);?//?undefined
console.log(person?.hobby?.work????"no?Work");?//?no?Work
可選鏈中的 ? 表示如果問號左邊表達式有值, 就會繼續(xù)查詢問號后面的字段。根據(jù)上面可以看出,用可選鏈可以大量簡化類似繁瑣的前置校驗操作,而且更安全。
注意:?. 不能用來賦值。
賦值,我們通常采用 ?可選鏈操作符和 空值合并運算符 進行搭配使用
let?user={
??name:'Symbol盧',
??age:18,
??skill:{
????Web:{
??????html:'50%',
??????css:'60%',
??????js:'80%'
????},
????Server:{
??????node:'80%',
??????php:'50%',
??????net:'60%'
????}
??}
}
console.log(user.name,"name")//Symbol盧?name
console.log(user.like,"like")//undefined?"like"
//我們平常的工作中,會這樣使用,當我們的對象里面沒有這個屬性的時候,這樣給他一個默認值
console.log(user.like?||?'寫代碼',"like2")//寫代碼?like2?
//ES2020?的??
console.log(user.sex??'男',"sex");??//不存在這個sex屬性,就會走后面的默認值,如果存在這個sex屬性,就不會走后面的默認值
console.log(user.skill.Web.js,"js")//80%?js
//console.log(user.skill.Database.MySql,"MySql")//Uncaught?TypeError:?Cannot?read?property?'MySql'?of?undefined
//空值合并運算符??與?可選鏈?相結(jié)合,可以很輕松處理多級查詢并賦予默認值問題
console.log(user?.skill?.Database?.MySql????'88%',"MySql")
BigInt
關于js的浮點數(shù)的一個精度問題,最典型的就是 ?0.1+0.2!= 0.3
console.log(0.1+0.2,'0.1+0.2')//0.30000000000000004?"0.1+0.2"
console.log(0.1+0.2==0.3,"0.1+0.2==0.3")//false?"0.1+0.2==0.3"
JavaScript可以處理的最大數(shù)字是2 ^ 53,通過MAX_SAFE_INTEGER可以查出這個值:
JavaScript 中 Number 類型只能安全的表示-(2^53 -1)至 2^53 -1 范的值,即 Number.MIN_SAFE_INTEGER 至 Number.MAX_SAFE_INTEGER,超出這個范圍的整數(shù)計算或者表示會丟失精度。
let?maxNum=Number.MAX_SAFE_INTEGER;
console.log(maxNum)//9007199254740991
let?num1=Number.MAX_SAFE_INTEGER+1;
let?num2=Number.MAX_SAFE_INTEGER+2;
console.log(num1==num2,"num1==num2")//true??超過這個范圍,就精度丟失了
為解決此問題,ES2020 提供一種新的數(shù)據(jù)類型:BigInt。使用 BigInt 有兩種方式:
在整數(shù)字面量后面加 n。
let?bigIntNum1=9007199254740999n;
console.log(typeof?bigIntNum1)//bigint
使用 BigInt函數(shù)。
let?bigIntNum2=BigInt(90071992547409999);
console.log(typeof?bigIntNum2)//bigint
接下來我們再對兩位數(shù)進行判斷:
console.log(bigIntNum1==bigIntNum2)//false
//已結(jié)解決了之前超過這個精度不能進行計算的問題
我們再通過 BigInt, 我們可以安全的進行大數(shù)整型計算。
let?BigNum=bigIntNum1+bigIntNum2;
console.log(BigNum.toString())//99079191802150999
注意:
BigInt是一種新的數(shù)據(jù)原始(primitive)類型。注意標準數(shù)字與BigInt數(shù)字不能混合使用。
typeof?9007199254740993n;?//?->?'bigint'
盡可能避免通過調(diào)用函數(shù) BigInt方式來實例化超大整型。因為參數(shù)的字面量實際也是Number類型的一次實例化,超出安全范圍的數(shù)字,可能會引起精度丟失。
動態(tài)導入
在項目中,某些功能可能很少使用,而導入所有依賴項可能只是浪費資源。現(xiàn)在可以使用async / await在需要時動態(tài)導入依賴項,可以在初始化的時候不全部加載邏輯資源,只進行按需加載,這樣可以讓首屏的渲染速度更快,雖然我們的前端工程化項目使用的webpack已經(jīng)很好支持了按需導入,但是現(xiàn)在能夠在2020正式的進入ES的規(guī)范,我們的js也是越來越強大了。
demo.js 導出模塊:
export?const?sum=(num1,num2)=>num1+num2;
動態(tài)導入:
let?fun=async(num1,num2)=>{
??let?model=await?import('./demo.js');
??console.log(model.sum(num1,num2),"兩個數(shù)的和")
}
fun(8,9)//17?"兩個數(shù)的和"
//報錯
//Access?to?script?at?'file:///C:/Users/Administrator/Desktop/es11Demo/demo.js'?from?origin?'null'?has?been?blocked?by?CORS?policy:?Cross?origin?requests?are?only?supported?for?protocol?schemes:?http,?data,?chrome,?chrome-extension,?https.
???//demo.js:1?Failed?to?load?resource:?net::ERR_FAILED
???//demo.html:13?Uncaught?(in?promise)?TypeError:?Failed?to?fetch?dynamically?imported?module:?file:///C:/Users/Administrator/Desktop/es11Demo/demo.js
//報錯需要在http服務器環(huán)境下,才可以
在當前項目的 根目錄上創(chuàng)建http服務器 (電腦里面已經(jīng)有node環(huán)境)
npm i http-server -g ? ?安裝依賴
然后在目錄 里面 執(zhí)行 http-server
globalThis
JavaScript 在不同的環(huán)境獲取全局對象有不同的方式,NodeJS 中通過 global, Web 中通過 window, self 等,有些甚至通過 this 獲取,但通過 this 是及其危險的,this 在 JavaScript 中異常復雜,它嚴重依賴當前的執(zhí)行上下文,這些無疑增加了獲取全局對象的復雜性。
全局變量 window:是一個經(jīng)典的獲取全局對象的方法。但是它在 Node.js 和 Web Workers 中并不能使用
全局變量 self:通常只在 Web Workers 和瀏覽器中生效。但是它不支持 Node.js。
全局變量 global:只在 Node.js 中生效
我們寫的一個js文件,可能在瀏覽器上運行,也可能在node環(huán)境下運行,也可能在 ?Web Workers 環(huán)境中運行,
這時候的這個全局變量就不統(tǒng)一我們可以使用以下的方法去做一個判斷,過去獲取全局對象,可通過一個全局函數(shù):
var?getGlobal?=?function?()?{
??if?(typeof?self?!==?'undefined')?{?return?self;?}
??if?(typeofwindow?!==?'undefined')?{?returnwindow;?}
??if?(typeof?global?!==?'undefined')?{?return?global;?}
??thrownewError('unable?to?locate?global?object');
};
var?globals?=?getGlobal();
而到我們的ES11中為我們提供了 globalThis,
而 globalThis 目的就是提供一種標準化方式訪問全局對象,有了 globalThis后,你可以在任意上下文,任意時刻都能獲取到全局對象。
globalThis 提供了一個標準的方式來獲取不同環(huán)境下的全局 this 對象(也就是全局對象自身),所以不用擔心運行環(huán)境。
//?worker.js
console.log(globalThis?===?self)?//true
//?node.js
console.log(globalThis?===?global)?//true
//?瀏覽器
console.log(globalThis?===?window)?//true
Promise.all 缺陷
都知道 Promise.all 具有并發(fā)執(zhí)行異步任務的能力。但它的最大問題就是如果其中某個任務出現(xiàn)異常(reject),所有任務都會掛掉,Promise 直接進入 reject 狀態(tài)。
想象這個場景:你的頁面有三個區(qū)域,分別對應三個獨立的接口數(shù)據(jù),使用 Promise.all 來并發(fā)三個接口,如果其中任意一個接口服務異常,狀態(tài)是 reject,這會導致頁面中該三個區(qū)域數(shù)據(jù)全都無法渲染出來,因為任何 reject 都會進入 catch 回調(diào), 很明顯,這是無法接受的,如下:
let?a=?new?Promise((resolve,reject)=>{
??//異步操作...
??resolve({?code:?200,msg:"請求成功"})
})
let?b=?new?Promise((resolve,reject)=>{
??//異步操作...
??resolve({?code:?200,msg:"請求成功"})
})
let?c=?new?Promise((resolve,reject)=>{
??//異步操作...
??reject({?code:?500,msg:"服務器出現(xiàn)異常"})
})
//使用Promise.all?進行并發(fā)執(zhí)行異步任務
Promise.all([a,b,c])
.then((res)?=>?{
????//?只有?上面所有的請求都是?resolve?(成功)?的時候才會進入此回調(diào)中
????console.log(res,"res")
})
.catch((error)?=>?{
????//?上面的請求中,只要有一個是reject?(失敗)?就會進入此回調(diào)
????console.log(error,"error")
????//?error:?{code:?500,?msg:?"服務異常"}
})
Promise.allSettled
當我們處理多個promise時,尤其是當它們相互依賴時,記錄每個事件在調(diào)試中發(fā)生的錯誤可能很有用。使用Promise.allSettled,它會創(chuàng)建一個新的promise,在所有promise完成后返回一個包含每個promise結(jié)果的數(shù)組。
let?a=?new?Promise((resolve,reject)=>{
??//異步操作...
??resolve({?code:?200,msg:"請求成功"})
})
let?b=?new?Promise((resolve,reject)=>{
??//異步操作...
??resolve({?code:?200,msg:"請求成功"})
})
let?c=?new?Promise((resolve,reject)=>{
??//異步操作...
??reject({?code:?500,msg:"服務器出現(xiàn)異常"})
})
//使用進行并發(fā)請求
Promise.allSettled([a,b,c]).then((data=>{
??console.log(data,"data")
}))
//?返回的數(shù)據(jù)中?,status:?"fulfilled"?表示請求成功,status:?"rejected"?表示請求失敗
Promise.allSettled 的優(yōu)勢
Promise.allSettled跟``Promise.all類似 都是進行并發(fā)請求,但是,我們在上面的兩個例子中,顯然是已經(jīng)看到了他們的一些區(qū)別,在使用Promise.all進行并發(fā)請求的時候,只要有一個請求出現(xiàn)問題(異常),所有的請求正常的也都不能拿到數(shù)據(jù),但是在我們的業(yè)務的開發(fā)中,我們需要保障我們業(yè)務的最大的可訪問性,就是在我們執(zhí)行并發(fā)任務中,不管我這個并發(fā)任務中的一任何個任務是正常還是異常,我們都需要拿到返回的對應的狀態(tài),在ES11中Promise.allSettled就為我們解決了這個問題,它和Promise.all類似,參數(shù)接受一個Promise的數(shù)組,返回一個新的Promise,也就是說當Promise全部處理完成后,我們可以拿到每個Promise的狀態(tài), 而不管是否處理成功。我們可以在then里面通過filter來過濾出想要的業(yè)務邏輯結(jié)果,這樣就解決了Promise.all` 的缺陷。
最后
如果你覺得這篇內(nèi)容對你挺有啟發(fā),我想邀請你幫我三個小忙:
點個「在看」,讓更多的人也能看到這篇內(nèi)容(喜歡不點在看,都是耍流氓 -_-)
歡迎加我微信「qianyu443033099」拉你進技術群,長期交流學習...
關注公眾號「前端下午茶」,持續(xù)為你推送精選好文,也可以加我為好友,隨時聊騷。


