ES11規範於今年的年初完成,引入了許多新標準,本文講着重研究下其中幾個實用且有趣的新標準
嚴格限制一些用於內部使用的Class變量,只須要在變量前添加#,就可使其成爲私有變量,而且沒法在class外部直接訪問javascript
下面咱們以一個簡單的前端
class Hero { #aggressivity = 0 constructor (aggressivity){ this.#aggressivity = aggressivity } getHurt(){ return this.#aggressivity } setAggressivity(aggressivity){ this.#aggressivity = aggressivity } } const shooter = new Hero(100) let hurt = shooter.getHurt() console.log(hurt) //100 console.log(shooter.#aggressivity) //Error : Uncaught SyntaxError: Private field '#aggressivity' must be declared in an enclosing class
上面代碼咱們會發現,沒法直接進行訪問#aggressivity,將拋出異常
只能經過class裏進行訪問,可經過統一class的公共方法進行統一修改java
假設目前射手攜帶了狂暴技能,提高了10%傷害,咱們能夠經過setAggressivity來修改攻擊力正則表達式
let aggressivity = parseInt(hurt * 1.1) shooter.setAggressivity(aggressivity) console.log(shooter.getHurt()) // 110
談及這個新特性以前,咱們先簡單回顧下Promise.all以及Promise.race,推測下爲何須要Promise.allSettled這個新特性編程
Promise.all:能夠將多個Promise實例包裝成一個新的Promise實例。同時,成功和失敗的返回值是不一樣的,成功的時候返回的是一個結果數組,而失敗的時候則返回最早被reject失敗狀態的值數組
let p1 = new Promise((resolve, reject) => { resolve('成功了') }) let p2 = new Promise((resolve, reject) => { resolve('success') }) let p3 = Promse.reject('失敗') Promise.all([p1, p2]).then((result) => { console.log(result) //['成功了', 'success'] }).catch((error) => { console.log(error) }) Promise.all([p1,p3,p2]).then((result) => { console.log(result) }).catch((error) => { console.log(error) // 失敗了,打出 '失敗' })
Promise.race:返回一個promise,一旦某個Promise觸發resolve或者reject,就直接返回該promise結果狀態promise
const promise1 = new Promise((resolve, reject) => { setTimeout(resolve, 500, 'one'); }); const promise2 = new Promise((resolve, reject) => { setTimeout(resolve, 100, 'two'); }); Promise.race([promise1, promise2]).then((value) => { console.log(value); }); //輸出 "two" 由於promise2返回結果比promise1快
有時候咱們可能須要知道全部的結果作一些操做,並不關心其執行結果是否成功,在沒有Promise.allSettled以前,咱們須要本身實現,可經過以下實現Promise.allSettled瀏覽器
let allSettled = (funcArr) => { return new Promise((resolve) => { let sttled = 0 let result = [] for(let index = 0;index<funcArr.length;index++){ const element = funcArr[index] element .then(res => { result[index] = { status: 'fulfilled', value: res } }) .catch(err => { result[index] = { status: 'rejected', reason: err } }) .finally(() => { ++sttled === funcArr.length && resolve(result) }) } }) } //使用 const promises = [ Promise.reject('c'), Promise.resolve('a'), Promise.resolve('b'), ]; allSettled(promises).then(res => { console.log(res) }) // 打印結果 // [{"status":"rejected","reason":"c"}, // {"status":"fulfilled","value":"a"}, // {"status":"fulfilled","value":"b"}]
而Promise.allSettled新特性出來後,咱們能夠直接使用而不須要單獨去實現了安全
const promises = [ Promise.reject('c'), Promise.resolve('a'), Promise.resolve('b'), ]; Promise.allSettled(promises).then(res =>{ console.log(res) }) // 打印結果 // [{"status":"rejected","reason":"c"}, // {"status":"fulfilled","value":"a"}, // {"status":"fulfilled","value":"b"}]
返回結果裏會將返回一個數組,包含了全部成功與失敗的結果,數組每項爲對象,均含有status屬性,對應fulfilled和rejected。
當狀態爲fulfilled時,表明着成功,包含一個value,表明着成功的結果
當狀態爲rejected時,表明着失敗,包含一個reason,表明着失敗的緣由async
JS中缺乏顯式整數類型經常使人困惑。許多編程語言支持多種數字類型,如浮點型、雙精度型、整數型和雙精度型,但JS卻不是這樣。在JS中,按照IEEE 754-2008標準的定義,全部數字都以雙精度64位浮點格式表示。
在此標準下,沒法精確表示的很是大的整數將自動四捨五入。確切地說,JS 中的Number類型只能安全地表示-9007199254740991 (-(2^53-1)) 和9007199254740991(2^53-1)之間的整數,任何超出此範圍的整數值均可能失去精度。
console.log(9999999999999999); //10000000000000000
JS 提供Number.MAX_SAFE_INTEGER常量來表示 最大安全整數,Number.MIN_SAFE_INTEGER常量表示最小安全整數:
// 注意最後一位的數字 const A = Number.MAX_SAFE_INTEGER + 1 const B = Number.MAX_SAFE_INTEGER + 2 console.log(Number.MAX_SAFE_INTEGER) //9007199254740991 console.log(A) //9007199254740992 console.log(B) //9007199254740992 console.log(A === B) //true
當數據超出範圍就會失去精度,達不到咱們預期的結果。
BigInt橫空出世,能夠在標準JS中執行對大整數的算術運算,沒必要擔憂精度損失風險
建立BigInt數據類型的方式很是簡單,在整數後面追加n便可,或者經過BigInt()進行建立實例
const bigint = 999999999999999999n const bigintByMethod = BigInt('999999999999999999') console.log(bigint) //999999999999999999n console.log(bigintByMethod) //999999999999999999n console.log(bigint === bigintByMethod) //true //布爾值 console.log(BigInt(true)) //1n console.log(BigInt(false)) //0n console.log(typeof bigint) //"bigint"
BigInt 與 Number是兩種數據類型,沒法進行運算,能夠進行大小比較
console.log(88n == 88) //true console.log(88n === 88) //false console.log(88n+1) //Error =>Uncaught TypeError: Cannot mix BigInt and other types, use explicit conversions
BigInt之間,除了一元加號(+)運算符外,其餘都可用於BigInt
console.log(1n + 2n) //3n console.log(1n - 2n) //-1n console.log(+ 1n) //Uncaught TypeError: Cannot convert a BigInt value to a number console.log(- 1n) //-1n console.log(10n * 20n) //200n console.log(23n%10n) //3n console.log(20n/10n) //2n ......
須要注意的是,除法運算符會自動向下舍入到最接近的整數
console.log(25n / 10n) //2n console.log(29n / 10n) //2n
最後還有個注意點就是,Boolean類型和BigInt類型的轉換時,處理方式和Number類型,只要不是0n,BigInt就被視爲true
if (5n) { // 這裏代碼塊將被執行 } if (0n) { // 這裏代碼塊不會執行 }
新增一個邏輯運算符??,處理null和undefined,工做原理與邏輯or( || )相似,可是與此相反
||若是爲真即返回左側值,不然返回右側
0 || 5 // return 5 "" || 5 // return 5 "前端公蝦米" || 'V5' //return "前端公蝦米"
??若是爲null或者undefined,即返回右側,不然返回左側
0 ?? 5 //return 0 "" ?? 5 //return "" null ?? 5 // return 5 undefined ?? 5 // return 5 false ?? 5 //return false NaN ?? 5 // return NaN
在使用該??運算符時,須要注意的是
"前端公蝦米" || undefined ?? "Sneaker" //Uncaught SyntaxError: Unexpected token '??' "前端公蝦米" && undefined ?? "Sneaker" //Uncaught SyntaxError: Unexpected token '??' ("前端公蝦米" || undefined) ?? "公^衆^號" //"前端公蝦米" ("回覆學習領取視頻資料" && null) ?? "一塊兒學習" //"一塊兒學習"
平常開發中,很多開發者會碰到Cannot read property XXX of undefined,拋出沒法從未定義的數據中讀取某個字段
可選鏈運算符在查找嵌套對象時,找到鏈中的第一個undefined或者null後會當即終止,並返回undefined,而不會不斷向下查找而致使拋錯
const obj = { foo: { bar: { baz: 42, }, }, } console.log(obj.fo.bar.baz) //Uncaught TypeError: Cannot read property 'bar' of undefined 在諸如此類的對象裏,咱們一般進行數據安全檢查來訪問嵌套對象,不然將拋錯 if(obj&&obj.foo&&obj.foo.bar){ console.log(obj.foo.bar.baz) // 42 }
在可選鏈運算符可以使用的如今,咱們只需這樣進行屬性的讀取
console.log(obj?.foo?.bar?.baz) //42 console.log(obj.foo.bar?.baz) //42
在標準的import導入中,是靜態導入的,全部被導入的模塊是在加載時就被編譯的,沒法按需編譯。當咱們須要條件導入的時候,都只能使用require().
但如今,咱們有辦法改善此類狀況了,由於動態導入能夠有效的減小未使用代碼的編譯,能夠提升首屏加載速度,按需加載。
那麼,爲何咱們須要動態導入呢?
//通用導入方式 import("/module/sneaker/test.js") .then(module => { //模塊相關操做 }) //await const getModule = await import("/module/sneaker/test.js") //經過async await const getUserInfo = async (hasLogin) => { if(!hasLogin){ const user = await import("/module/sneaker/user.js") user.getInfo() } }
基於String原型上的一個新方法,容許咱們匹配一個字符串和一個正則表達式,返回值是全部匹配結果的迭代器。
能夠經過for...of遍歷或者操做符...、Array.from將結果迭代器轉換成數組
const string = 'Hello Sneaker,Where is the library?' const regex = /[A-W]/g const matches = string.matchAll(regex) console.log(...matches) //["H", index: 0, input: "Hello Sneaker,Where is the library?", groups: undefined] //["S", index: 6, input: "Hello Sneaker,Where is the library?", groups: undefined] //["W", index: 14, input: "Hello Sneaker,Where is the library?", groups: undefined]
這是爲了提供一種訪問全局對象的標準方法。
在瀏覽器中,咱們可使用window/self/frames來訪問全局對象,但對於Web Workers只能使用self,Node中又徹底不一樣,須要使用global。
在globalThis成爲標準以前,獲取全局對象咱們可能須要這麼作
const globalObj = (()=>{ if(self) return self if(window) return window if(global) return global throw new Error('Sorry!No global obj found') })
//Browser globalThis === window //true //Webworker globalThis === self //true //Node globalThis === global //true
今後實現全局對象的大一統!
export * as ns from './module //等同於 import * as ns from './module' export {ns}
導入特定命名空間實則並無導入模塊,只是對模塊進行轉發,致使在此模塊中不可直接使用此模塊
特性不少但有的頗有趣,好比可選鏈和空位合併運算符,屢試不爽,至於有多爽,你試了才知道。新特性日常不寫仍是容易忽略淡忘的,建議日常能夠下意識的常常回顧運用,一塊兒學習一塊兒成長。
本文首發公衆號【前端公蝦米】,若有錯誤,還望聯繫我指出【y3517320520】