ES11來了,不進來看看嘛

前言

ES2020 (ES11)是 ECMAScript 對應 2020 年的版本。這個版本不像 ES6 (ES2015)那樣包含大量新特性。但也添加了許多有趣且有用的特性。本文以簡單的代碼示例來介紹 ES2020新特性。這樣,你能夠很快理解這些新功能,而不須要多麼複雜的解釋,好了,廢話很少說咱們進入正文🔛php

私有變量

類的主要做用之一是將咱們的代碼包含在可重用的模塊中。因此會在許多不一樣地方使用到同一個類,可是又的類裏面的一些屬性,爲了安全或者是其餘的目的,不想讓其餘的類可以去訪問他,修改他,只能他本身用,對於一些學過c#,java等語言的同窗來講是比較好理解的,就是 Private一個訪問修飾符,那麼在咱們的js當中該怎麼辦了,css

別擔憂,他們有的咱js也有,在ES11中也爲咱們提供了私有變量,經過在變量或函數前面添加一個哈希符號#,能夠將它們設爲私有屬性,只在類內部可用。html

這是咱們普通的一個類前端

class Money{
  constructor(money){
    this.money=money;
  }
}
let RMB=new Money(999);
RMB.money=999999;//這還了得,怎麼能夠隨便改錢的金額呢
console.log(RMB.money);//能夠經過對象的形式去訪問
複製代碼

因爲安全,咱們不能讓其餘的類來隨便更改咱們類裏面的屬性的值,咱們可使用 私有屬性,是隻能在類裏面進行訪問java

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
複製代碼

上面的代碼報錯了,哭唧唧img,拿不到私有屬性的值了,怎麼辦??node

我須要使用我類裏面的錢,怎麼獲取imgwebpack

咱們能夠在類裏面寫兩個方法,取數據,寫入數據,能夠進行修改,可是你不能任意改,必須經過個人方法去改,咱們能夠看看下面的代碼web

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());
複製代碼

好了,私有變量(屬性),咱們就說到這裏了,下面咱們來看看空值合併運算符吧!chrome

空值合併運算符

在咱們日常的工做中,在取一個對象裏面的屬性,若是這個屬性沒有值,咱們會這樣給他一個默認值npm

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屬性,就不會走後面的默認值
複製代碼

**空值合併運算符(*??*)**是一個邏輯運算符。當左側操做數爲 null 或 undefined 時,其返回右側的操做數。不然返回左側的操做數。

??和 || 的區別是什麼呢??

他們兩個最大的區別就是 ' '和 0,??的左側 爲 ' '或者爲 0 的時候,依然會返回左側的值;

|| 會對左側的數據進行boolean類型轉換,因此' '和 0 會被轉換成false,返回右側的值

可選鏈操做符

減小訪問深層對象時判斷屬性存不存在的問題。

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
複製代碼

可選鏈中的 ? 表示若是問號左邊表達式有值, 就會繼續查詢問號後面的字段。根據上面能夠看出,用可選鏈能夠大量簡化相似繁瑣的前置校驗操做,並且更安全。

注意?. 不能用來賦值。

賦值,咱們一般採用 可選鏈操做符空值合併運算符 進行搭配使用

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
//空值合併運算符  與 可選鏈 相結合,能夠很輕鬆處理多級查詢並賦予默認值問題
console.log(user?.skill?.Database?.MySql ?? '88%',"MySql")
複製代碼

BigInt

關於js的浮點數的一個精度問題,最典型的就是 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能夠處理的最大數字是2 ^ 53,經過MAX_SAFE_INTEGER能夠查出這個值:

JavaScript 中 Number 類型只能安全的表示-(2^53 -1)2^53 -1 範的值,即 Number.MIN_SAFE_INTEGERNumber.MAX_SAFE_INTEGER,超出這個範圍的整數計算或者表示會丟失精度。

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 提供一種新的數據類型:BigInt。使用 BigInt 有兩種方式:

  1. 在整數字面量後面加 n
let bigIntNum1=9007199254740999n;
console.log(typeof bigIntNum1)//bigint
複製代碼
  1. 使用 BigInt 函數。
let bigIntNum2=BigInt(90071992547409999);
console.log(typeof bigIntNum2)//bigint
複製代碼

接下來咱們再對兩位數進行判斷:

console.log(bigIntNum1==bigIntNum2)//false
//已結解決了以前超過這個精度不能進行計算的問題
複製代碼

咱們再經過 BigInt, 咱們能夠安全的進行大數整型計算。

let BigNum=bigIntNum1+bigIntNum2;
console.log(BigNum.toString())//99079191802150999
複製代碼

注意:

  1. BigInt 是一種新的數據原始(primitive)類型。注意標準數字與 BigInt 數字不能混合使用。
typeof 9007199254740993n; // -> 'bigint'
複製代碼
  1. 儘量避免經過調用函數 BigInt 方式來實例化超大整型。由於參數的字面量實際也是 Number 類型的一次實例化,超出安全範圍的數字,可能會引發精度丟失。

動態導入

在項目中,某些功能可能不多使用,而導入全部依賴項可能只是浪費資源。如今可使用async / await在須要時動態導入依賴項,能夠在初始化的時候不所有加載邏輯資源,只進行按需加載,這樣可讓首屏的渲染速度更快,雖然咱們的前端工程化項目使用的webpack已經很好支持了按需導入,可是如今可以在2020正式的進入ES的規範,咱們的js也是愈來愈強大了。

demo.js 導出模塊:

export const sum=(num1,num2)=>num1+num2;
複製代碼

動態導入:

let fun=async(num1,num2)=>{
  let model=await import('./demo.js');
  console.log(model.sum(num1,num2),"兩個數的和")
}
fun(8,9)//17 "兩個數的和"

//報錯
//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服務器環境下,才能夠
複製代碼

在當前項目的 根目錄上建立http服務器 (電腦裏面已經有node環境)

npm i http-server -g 安裝依賴

而後在目錄 裏面 執行 http-server

globalThis

JavaScript 在不一樣的環境獲取全局對象有不一樣的方式,NodeJS 中經過 global, Web 中經過 window, self 等,有些甚至經過 this 獲取,但經過 this 是及其危險的,this 在 JavaScript 中異常複雜,它嚴重依賴當前的執行上下文,這些無疑增長了獲取全局對象的複雜性。

  • 全局變量 window:是一個經典的獲取全局對象的方法。可是它在 Node.js 和 Web Workers 中並不能使用

  • 全局變量 self:一般只在 Web Workers 和瀏覽器中生效。可是它不支持 Node.js。

  • 全局變量 global:只在 Node.js 中生效

咱們寫的一個js文件,可能在瀏覽器上運行,也可能在node環境下運行,也可能在 Web Workers 環境中運行,

這時候的這個全局變量就不統一咱們可使用如下的方法去作一個判斷,過去獲取全局對象,可經過一個全局函數:

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 提供了一個標準的方式來獲取不一樣環境下的全局 this 對象(也就是全局對象自身),因此不用擔憂運行環境。

// worker.js
console.log(globalThis === self) //true
// node.js
console.log(globalThis === global) //true
// 瀏覽器
console.log(globalThis === window//true
複製代碼

Promise.all 缺陷

都知道 Promise.all 具備併發執行異步任務的能力。但它的最大問題就是若是其中某個任務出現異常(reject),全部任務都會掛掉,Promise 直接進入 reject 狀態。

想象這個場景:你的頁面有三個區域,分別對應三個獨立的接口數據,使用 Promise.all 來併發三個接口,若是其中任意一個接口服務異常,狀態是 reject,這會致使頁面中該三個區域數據全都沒法渲染出來,由於任何 reject 都會進入 catch 回調, 很明顯,這是沒法接受的,以下:

let a= new Promise((resolve,reject)=>{
  //異步操做...
  resolve({ code200,msg:"請求成功"})
})
let b= new Promise((resolve,reject)=>{
  //異步操做...
  resolve({ code200,msg:"請求成功"})
})
let c= new Promise((resolve,reject)=>{
  //異步操做...
  reject({ code500,msg:"服務器出現異常"})
})
//使用Promise.all 進行併發執行異步任務
Promise.all([a,b,c])
.then((res) => {
    // 只有 上面全部的請求都是 resolve (成功) 的時候纔會進入此回調中
    console.log(res,"res")
})
.catch((error) => {
    // 上面的請求中,只要有一個是reject (失敗) 就會進入此回調
    console.log(error,"error")
    // error: {code: 500, msg: "服務異常"}
})
複製代碼

Promise.allSettled

當咱們處理多個promise時,尤爲是當它們相互依賴時,記錄每一個事件在調試中發生的錯誤可能頗有用。使用Promise.allSettled,它會建立一個新的promise,在全部promise完成後返回一個包含每一個promise結果的數組。

let a= new Promise((resolve,reject)=>{
  //異步操做...
  resolve({ code200,msg:"請求成功"})
})
let b= new Promise((resolve,reject)=>{
  //異步操做...
  resolve({ code200,msg:"請求成功"})
})
let c= new Promise((resolve,reject)=>{
  //異步操做...
  reject({ code500,msg:"服務器出現異常"})
})
//使用進行併發請求
Promise.allSettled([a,b,c]).then((data=>{
  console.log(data,"data")
}))

// 返回的數據中 ,status: "fulfilled" 表示請求成功,status: "rejected" 表示請求失敗
複製代碼

image-20200713080751426

Promise.allSettled 的優點

Promise.allSettled跟``Promise.all相似 都是進行併發請求,可是,咱們在上面的兩個例子中,顯然是已經看到了他們的一些區別,在使用Promise.all進行併發請求的時候,只要有一個請求出現問題(異常),全部的請求正常的也都不能拿到數據,可是在咱們的業務的開發中,咱們須要保障咱們業務的最大的可訪問性,就是在咱們執行併發任務中,無論我這個併發任務中的一任何個任務是正常仍是異常,咱們都須要拿到返回的對應的狀態,在ES11中Promise.allSettled就爲咱們解決了這個問題,它和Promise.all相似,參數接受一個Promise的數組,返回一個新的Promise,也就是說當Promise所有處理完成後,咱們能夠拿到每一個Promise的狀態, 而不論是否處理成功。咱們能夠在then裏面經過filter來過濾出想要的業務邏輯結果,這樣就解決了Promise.all` 的缺陷。

相關文章
相關標籤/搜索