可選鏈 (Optional chaining)
可選鏈 讓我們?cè)诓樵兙哂卸鄬蛹?jí)的對(duì)象時(shí),不需要再進(jìn)行冗余的各種前置校驗(yàn)
例如日常開發(fā)中楞艾,我們經(jīng)常會(huì)遇到這種查詢
let name = user && user.info && user.info.name;
又或者是這種
let age = user && user.info && user.info.getAge && user.info.getAge();
如果在任何級(jí)別的對(duì)象中都有 undefined
或者 null
的嵌套對(duì)象着饥,如果不進(jìn)行檢查犀农,那么很容易命中 Uncaught TypeError: Cannot read property...
這種錯(cuò)誤,這很有可能讓你的程序崩潰宰掉。因此呵哨,我們必須檢查每個(gè)級(jí)別,以確保當(dāng)它遇到 undefined 或 null 對(duì)象時(shí)不會(huì)崩潰轨奄。
使用可選鏈運(yùn)算符孟害,只需要使用 ?.
來(lái)訪問嵌套對(duì)象。而且如果碰到 undefined 或 null 屬性挪拟,那么他只會(huì)返回 undefined挨务。
使用可選鏈,上面的代碼可改為:
let name = user?.info?.name;
let age = user?.info?.getAge?.();
可選鏈中的 ?
表示如果聞號(hào)左邊的表達(dá)式有值玉组,就會(huì)繼續(xù)查詢問好后面的字段
空值合并運(yùn)算符 (Nullish coalescing Operator)
undefined 或 null 值所產(chǎn)生的另一個(gè)問題谎柄,如果我們想要的變量為 undefined 或 null,則必須給變量設(shè)置默認(rèn)值球切。例如:
const a = b || '暫無(wú)數(shù)據(jù)';
當(dāng)使用 ||
運(yùn)算符將 b 賦值給 a 時(shí)谷誓,如果 b 被定義為 undefined,我們就必須設(shè)置一個(gè)默認(rèn)值吨凑。
運(yùn)算符 ||
的問題在于捍歪,在 JS 中,所有類似于 0鸵钝、false 或空字符串之類的值糙臼,在進(jìn)行邏輯操作符判斷時(shí),都會(huì)自動(dòng)轉(zhuǎn)化為 false恩商,如果用戶輸入的本身就是 0变逃,a 也會(huì)被賦值為 暫無(wú)數(shù)據(jù)
,就會(huì)出現(xiàn)邏輯錯(cuò)誤怠堪。
為了解決這個(gè)問題揽乱,創(chuàng)建了 nullish
合并運(yùn)算符,用 ??
表示粟矿。有了它凰棉,我們僅在第一項(xiàng)為 null 或 undefined 時(shí)設(shè)置默認(rèn)值。
使用無(wú)效的合并運(yùn)算符陌粹,以上表達(dá)式可改為:
const a = b ?? '暫無(wú)數(shù)據(jù)';
通過 # 給 class 添加私有變量
class Counter {
#num = 10;
increment() {
this.#num ++;
}
getNum() {
return this.#num;
}
}
const counter = new Counter()
counter.increment()
console.log(counter.getNum()) // 11
console.log(counter.#num) // SyntaxError
在 ES2020 中撒犀,通過 #
可以給 class 添加私有變量。在 class 的外部我們無(wú)法獲取該值。這樣就不需要使用閉包來(lái)隱藏不想暴露給外籍的私有變量或舞。
BigInt
Js 中 Number 類型只能安全地表示 -(2^53-1)
至 2^53-1
范圍內(nèi)的值荆姆,即 Number.MIN_SAFE_INTEGER
至 Number.MAX_SAFE_INTEGER
, 超出這個(gè)范圍的整數(shù)計(jì)算或者表示會(huì)丟失精度。
let num = Number.MIN_SAFE_INTEGER; // 9007199254740991
num += 1; // 9007199254740992
// 再加 +1 后無(wú)法正常運(yùn)算
num += 1映凳; // 9007199254740992
// 兩個(gè)不同的值比較胆筒,返回 true
console.log(9007199254740992 === 9007199254740993); // true
為了解決這個(gè)問題,ES2020 提供了一種新的數(shù)據(jù)類型:BigInt
魏宽。
使用 BigInt 有兩種方式:
- 在整數(shù)字面量后面加
n
const bigIntNum = 9007199254740993n;
- 使用
BigInt
函數(shù)
通過 BigInt腐泻,可以安全地進(jìn)行大數(shù)整型計(jì)算const bigIntNum = BigInt(9007199254740993) const anotherBigIntNum = BigInt('9007199254740995')
const bigNumRet = 9007199254740993n + 9007199254740993n; bigNumRet.toString(); // "18014398509481986"
注意:
- BigInt 是一種新的數(shù)據(jù)原始類型
typeof 9007199254740993n; // 'bigint';
- 盡可能避免通過調(diào)用函數(shù)
BigInt
方式來(lái)實(shí)例化超大整型。因?yàn)閰?shù)的字面量實(shí)際也是 Number 類型的一次實(shí)例化队询,超出安全范圍的數(shù)字派桩,可能會(huì)引起精度丟失。
Promise.allSettled
Promise.all 缺陷
Promise.all
具有并發(fā)執(zhí)行異步任務(wù)的能力蚌斩,但是它最大的問題就是如果其中某個(gè)任務(wù)出現(xiàn)異常(reject)铆惑,所有任務(wù)都會(huì)掛掉,Promise 直接進(jìn)入 reject
狀態(tài)送膳。
Promise.all([
Promise.reject({ code: 500, message: ''服務(wù)異常 }),
Promise.resolve({ code: 200, list: [] }),
Promise.resolve({ code: 200, list: [] }),
]).then(res => {
// 如果其中一個(gè)任務(wù)是 reject员魏,則不會(huì)執(zhí)行到這個(gè)回調(diào)
RenderContent(res)
}).catch(error => {
// 本例中會(huì)執(zhí)行到這個(gè)回調(diào)
// error: { code: 500, message: '服務(wù)異常' }
})
我們需要一種機(jī)制,如果并發(fā)任務(wù)中叠聋,無(wú)論一個(gè)任務(wù)正乘貉郑或者異常,都會(huì)返回對(duì)應(yīng)的狀態(tài)(fulfilled 或者 rejected)與結(jié)果(業(yè)務(wù) value 或者 拒因 reason)碌补,在 then 里面通過 filter 來(lái)過濾出想要的業(yè)務(wù)邏輯結(jié)果虏束,這就能最大限度的保障業(yè)務(wù)當(dāng)前狀態(tài)的可訪問性,而 Promise.allSettled
就是解決這個(gè)問題的厦章。
Promise.allSettled(iterable)
iterable:一個(gè)可迭代的對(duì)象镇匀,例如 Array,其中每個(gè)成員都是 Promise
返回一個(gè)在所有給定的 promise resolved 或者 rejected 的 promise袜啃,并帶有一個(gè)對(duì)象數(shù)組汗侵,每個(gè)對(duì)象表示對(duì)應(yīng)的 promise 結(jié)果。
Promise.allSettled([
Promise.reject({ code: 500, message }),
Promise.resolve({ code: 200, list: [] }),
Promise.resolve({ code: 200, list: [] }),
]).then(res => {
/*
[
{ status: "rejected", reason: {...} },
{ status: "fulfilled", value: {...} },
{ status: "fulfilled", value: {...} },
]
*/
// 過濾掉 reject 狀態(tài)群发,盡可能多的保證頁(yè)面區(qū)域數(shù)據(jù)渲染
RenderContent(res.filter(item => {
return item.status !== 'rejected';
}));
})
dynamic-import
靜態(tài) import 和動(dòng)態(tài) import() 有各自的特點(diǎn)和使用場(chǎng)景晰韵。
static import 是沒有括號(hào)的,dynamic import() 是帶括號(hào)的熟妓。
用法區(qū)別:
// 有聲明提升雪猪,一般只放在頭部位置
static import: import xxx from 'xxx';
// 可以放在任何位置
dynamic import(): const xxx = import('xxx');
按需執(zhí)行邏輯資源都體現(xiàn)在某一個(gè)時(shí)間回調(diào)中去加載,為了首屏渲染速度更快滑蚯,很多時(shí)候都是按需加載。
el.onclick = () => {
import('/example.js').then(module => {
module.todo();
}).catch(err => {
// load error
})
}
globalThis
JavaScript 在不同的環(huán)境獲取全局對(duì)象有不同的方式,node 中通過 global告材,web 中通過 window坤次、self 等,有些甚至通過 this 獲取斥赋,但是通過 this 是極其危險(xiǎn)的缰猴,this 在 js 中很依賴當(dāng)前的執(zhí)行上下文。
globalThis
提供了標(biāo)準(zhǔn)的方式去獲取不同環(huán)境下的全局對(duì)象疤剑。它不想 window 或者 self 這些屬性滑绒,而是確保可以再有無(wú)窗口的環(huán)境下都可以正常工作隘膘,不必?fù)?dān)心它的運(yùn)行環(huán)境疑故。
- 過去獲取全局對(duì)象的方式,可通過一個(gè)全局函數(shù)
const getGlobal = () => { 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'); } const globals = getGlobal(); console.log(globals)
- 使用
globalThis
獲取全局對(duì)象console.log(globalThis)