JavaScript ES12 新特性搶先體驗

在上一篇文章中,我們介紹了ES2020的相關九大特性,里面不少實用的新特性讓我們受益良多。ES11屢試不爽的新特性,你用上了幾個?
而每年,JavaScript都會更新添加新的特性新標準,在今年ES2020發(fā)布了,而ES2020(ES12)也預計將在明年即2021年年中發(fā)布。每年的新特性都會經歷四個階段,而第四階段也就是最后一個階段,本文即將介紹的即提案4中的相關新特性,也是意味著這些新特性將很大程度的出現在下一個版本中
特性搶先知:
String.prototype.replaceAll 新增replaceAll Promise.any WeakRefs 邏輯運算符和賦值表達式 數字分隔符號
replaceAll
看到replaceAll這個詞,相比很容易聯想到replace。在JavaScript中,replace方法只能是替換字符串中匹配到的第一個實例字符,而不能進行全局多項匹配替換,唯一的辦法是通過正則表達式進行相關規(guī)則匹配替換
而replaceAll則是返回一個全新的字符串,所有符合匹配規(guī)則的字符都將被替換掉,替換規(guī)則可以是字符串或者正則表達式。
let?string?=?'I?like?前端,I?like?前端公蝦米'
//使用replace
let?replaceStr?=?string.replace('like','love')
console.log(replaceStr)??//?'I?love?前端,I?like?前端公蝦米'
//replace使用正則匹配所有
console.log(string.replace(/like/g,'love'))?//?'I?love?前端,I?love?前端公蝦米'
//使用replaceAll
let?replaceAllStr?=?string.replaceAll('like','love')
console.log(replaceAllStr)?//?'I?love?前端,I?love?前端公蝦米'
需要注意的是,replaceAll在使用正則表達式的時候,如果非全局匹配(/g),則replaceAll()會拋出一個異常
let?string?=?'I?like?前端,I?like?前端公蝦米'
console.log(string.replaceAll(/like/,'love'))?//TypeError
Promise.any
當Promise列表中的任意一個promise成功resolve則返回第一個resolve的結果狀態(tài) 如果所有的promise均reject,則拋出異常表示所有請求失敗
Promise.any([
??new?Promise((resolve,?reject)?=>?setTimeout(reject,?500,?'哎呀,我被拒絕了')),
??new?Promise((resolve,?reject)?=>?setTimeout(resolve,?1000,?'哎呀,她接受我了')),
??new?Promise((resolve,?reject)?=>?setTimeout(resolve,?2000,?'哎呀,她也接受我了')),
])
.then(value?=>?console.log(`輸出結果:?${value}`))
.catch?(err?=>?console.log(err))
//輸出
//輸出結果:哎呀,她接受我了
再來看下另一種情況
Promise.any([
??Promise.reject('Error?1'),
??Promise.reject('Error?2'),
??Promise.reject('Error?3')
])
.then(value?=>?console.log(`請求結果:?${value}`))
.catch?(err?=>?console.log(err))
//輸出
AggregateError:?All?promises?were?rejected
Promise.any與Promise.race十分容易混淆,務必注意區(qū)分,Promise.race 一旦某個promise觸發(fā)了resolve或者reject,就直接返回了該狀態(tài)結果,并不在乎其成功或者失敗
WeakRefs
使用WeakRefs的Class類創(chuàng)建對對象的弱引用(對對象的弱引用是指當該對象應該被GC回收時不會阻止GC的回收行為)
當我們通過(const、let、var)創(chuàng)建一個變量時,垃圾收集器GC將永遠不會從內存中刪除該變量,只要它的引用仍然存在可訪問。WeakRef對象包含對對象的弱引用。對對象的弱引用是不會阻止垃圾收集器GC恢復該對象的引用,則GC可以在任何時候刪除它。
WeakRefs在很多情況下都很有用,比如使用Map對象來實現具有很多需要大量內存的鍵值緩存,在這種情況下最方便的就是盡快釋放鍵值對占用的內存。
目前,可以通過WeakMap()或者WeakSet()來使用WeakRefs
舉個栗子
我想要跟蹤特定的對象調用某一特定方法的次數,超過1000條則做對應提示
let?map?=?new?Map()
function?doSomething(obj){
?...
}
function?useObject(obj){
?doSomething(obj)
??
??let?called?=?map.get(obj)?||?0
??called?++?
??
??if(called>1000){
?????console.log('當前調用次數已經超過1000次了,over')
??}
??
??map.set(obj,?called)
}
如上雖然可以實現我們的功能,但是會發(fā)生內存溢出,因為傳遞給doSomething函數的每個對象都永久保存在map中,并且不會被GC回收,因此我們可以使用WeakMap
let?wmap?=?new?WeakMap()
function?doSomething(obj){
?...
}
function?useObject(obj){
?doSomething(obj)
??
??let?called?=?wmap.get(obj)?||?0
??
??called?++
??
??if(called>1000){
?????console.log('當前調用次數已經超過1000次了,over')
??}
??
??wmap.set(obj,?called)
}
因為是弱引用,所以WeakMap、WeakSet的鍵值對是不可枚舉的
WeakSet和WeakMap相似,但是每個對象在WeakSet中的每個對象只可能出現一次,WeakSet中所有對象都是唯一的
let?ws?=?new?WeakSet()
let?foo?=?{}
let?bar?=?{}
ws.add(foo)
ws.add(bar)
ws.has(foo)?//true
ws.has(bar)?//true
ws.delete(foo)?//刪除foo對象
ws.has(foo)?//false?已刪除
ws.has(bar)?//仍存在
WeakSet與Set相比有以下兩個區(qū)別
WeakSet只能是對象集合,而不能是任何類型的任意值 WeakSet弱引用,集合中對象引用為弱引用,如果沒有其他對WeakSet對象的引用,則會被GC回收
最后,WeakRef實例有一個方法deref,返回引用的原始對象,如果原始對象被回收,則返回undefined
const?cache?=?new?Map();
const?setValue?=??(key,?obj)?=>?{
??cache.set(key,?new?WeakRef(obj));
};
const?getValue?=?(key)?=>?{
??const?ref?=?cache.get(key);
??if?(ref)?{
????return?ref.deref();
??}
};
const?fibonacciCached?=?(number)?=>?{
??const?cached?=?getValue(number);
??if?(cached)?return?cached;
??const?sum?=?calculateFibonacci(number);
??setValue(number,?sum);
??return?sum;
};
對于緩存遠程數據來說,這可能不是一個好主意,因為遠程數據可能會不可預測地從內存中刪除。在這種情況下,最好使用LRU之類的緩存。
邏輯運算符和賦值表達式
邏輯運算符和賦值表達式,新特性結合了邏輯運算符(&&,||,??)和賦值表達式而JavaScript已存在的 復合賦值運算符有:
操作運算符:+= ? -= ? *= ? /= ? %= ? **= 位操作運算符:&= ? ^= ? |= 按位運算符:<<= ? >>= ? >>>=
現有的的運算符,其工作方式都可以如此來理解
表達式:a op= b
等同于:a = a op b
邏輯運算符和其他的復合賦值運算符工作方式不同
表達式:a op= b
等同于:a = a op (a = b)
a?||=?b
//等價于
a?=?a?||?(a?=?b)
a?&&=?b
//等價于
a?=?a?&&?(a?=?b)
a???=?b
//等價于
a?=?a????(a?=?b)
為什么不再是跟以前的運算公式a = a op b一樣呢,而是采用a = a op (a = b)。因為后者當且僅當a的值為false的時候才計算賦值,只有在必要的時候才執(zhí)行分配,而前者的表達式總是執(zhí)行賦值操作
??=可用來補充/初始化缺失的屬性
const?pages?=?[
??{
???title:'主會場',
????path:'/'
??},
??{
????path:'/other'
??},
??...
]
??
for?(const?page?of?pages){
?page.title???=?'默認標題'
}
console.table(pages)
//(index)??title?????????path
//0????????"主會場"??????"/"
//1????????"默認標題"????"/other"
小結:
&&=:當LHS值存在時,將RHS變量賦值給LHS ||=:當LHS值不存在時,將RHS變量賦值給LHS ??=?:當LHS值為null或者undefined時,將RHS變量賦值給LHS
數字分隔符
數字分隔符,可以在數字之間創(chuàng)建可視化分隔符,通過_下劃線來分割數字,使數字更具可讀性
const?money?=?1_000_000_000
//等價于
const?money?=?1000000000
const?totalFee?=?1000.12_34
//等價于
const?totalFee?=?1000.1234
該新特性同樣支持在八進制數中使用
const?number?=?0o123_456
//等價于
const?number?=?0o123456
該新特性方便讀取數據,可以讓我們「打工人」更容易辨認"資產" 不過話說回來,小編的資產好像不配使用該特性...敲重點?。?!
本次所有新特性均介紹的第4階段,意味著將出現在下一個版本中的,沒有介紹階段3的,因為不確定是否一定會出現在下個版本中。本文介紹的新特性均可直接在最新版的谷歌瀏覽器中愉快體驗。
??看完三件事
如果你覺得這篇內容對你挺有啟發(fā),我想邀請你幫我三個小忙:
點贊,讓更多的人也能看到介紹內容(收藏不點贊,都是耍流氓-_-) 關注公眾號“前端勸退師”,不定期分享原創(chuàng)知識。 也看看其他文章
勸退師個人微信:huab119
也可以來我的GitHub博客里拿所有文章的源文件:
前端勸退指南:https://github.com/roger-hiro/BlogFN一起玩耍呀
