是時候學習/推廣一波可選鏈(Optional chaining)和空值合併(Nullish coalescing )了

最近工做中發現團隊有些同窗不太瞭解 Optional chainingNullish coalescing 兩個新的操做符,正好推廣一波shell

背景

Optional chainingNullish coalescing 目前都已經歸入 ECMA-262 標準中,不過兼容性還差得遠,以下: json

MDN 兼容表
兩個操做符的兼容幾乎一致,不過如今有了 babel,兼容都不是問題。不過仍是要注意使用前必定要確認項目是否支持這倆操做符,切勿只顧一時爽,至於如何兼容能夠看下方。

Optional chaining 介紹

Optional chaining 是爲了解決程序中鋪天蓋地的 Cannot read property 'foo' of undefined 錯誤或者是滿屏幕的 a && a.b && a.b.c && a.b.c.d 邏輯與運算符或者是三元操做符。 有了 Optional chaining,咱們能夠十分優雅的去獲取某些可能不存在的數據。緩存

Optional chaining 操做符的定義是:當左操做數爲空值時(nullundefined)中斷取值操做並返回 undefined。(方法調用爲方法爲空值時中斷調用並返回 undefined)。babel

const foo = a?.b?.c?.d;
複製代碼

比起一長串的邏輯與運算符,不但優雅美觀,並且方便、可讀性更高,邏輯與有時候會偷懶不寫,不過自從用了 Optional chaining,不再用偷懶了,屬性取值如此簡單穩定,不再怕屬性找不到了。ui

Optional chaining 有三種標準語法:spa

// 靜態屬性
a?.b?.c.d
// 動態屬性
a?.[b]?.c.d
// 方法調用
a?.b?.()
複製代碼

不過也須要注意 Optional chaining 後不能跟數字,由於存在語法上的重合。插件

a?.3:0;
a?.[3]
複製代碼

因此須要接數字時記得使用 []eslint

同時 Optional chaining 也支持 delete:code

delete a?.b?.c;
複製代碼

注意上述操做不管 a.b 的值只會刪除 a.b.c 不會刪除 a.bcdn

Nullish coalescing 介紹

再來看看 Nullish coalescingNullish coalescingOptional chaining 算是一對好基友,主要用來作一些默認值的設置。

Nullish coalescing 操做符的定義是:當左操做數爲空值時(nullundefined)返回右操做數,不然返回左操做數。

const foo = a?.b?.c?.d ?? 'bar';
複製代碼

有的同窗可能好奇這不是和邏輯或同樣嗎?

const foo = a?.b?.c?.d || 'bar';
複製代碼

其實仍是不同的 Nullish coalescing 從名字能夠看出來:空值合併,也就是隻有左操做數爲空值時纔會應用右操做數,而邏輯或使用的是假值進行判斷,在一些邊界狀況下如左操做數爲 0'' 空字符串時 Nullish coalescing 會更合理,能夠減小一些邊界值的判斷。

null ?? 'foo'; // 'foo'
undefined ?? 'foo'; // 'foo'
0 ?? 'foo'; // 0
'' ?? 'foo'; // ''

null || 'foo'; // 'foo'
undefined || 'foo'; // 'foo'
0 || 'foo'; // 'foo'
'' || 'foo'; // 'foo'
複製代碼

如何使用

這兩個新的操做符其實如今已經包含在新版的 preset-env 中,若是你的項目 preset-env 較新的化,那恭喜🎉,你不須要作什麼額外的操做就能夠用上了。

不過若是是較舊版的 preset-env,那麼須要安裝上相應的插件來進行啓用:

yarn add @babel/plugin-proposal-optional-chaining @babel/plugin-proposal-nullish-coalescing-operator --dev
複製代碼

安裝完成後不要忘記在 babel 配置中啓用:

{
  "plugins": ["@babel/plugin-proposal-optional-chaining", "@babel/plugin-proposal-nullish-coalescing-operator"]
}
複製代碼

Babel 轉義

順便看一下 babel 是如何轉義 Optional chainingNullish coalescing 的。

Optional chaining 的轉義

a?.b?.[c]?.()
delete a?.b?.c
// babel 轉義後 =====> 
"use strict";
var _a, _a$b, _a$b$c, _a2, _a2$b;
(_a = a) === null || _a === void 0 ? void 0 : (_a$b = _a.b) === null || _a$b === void 0 ? void 0 : (_a$b$c = _a$b[c]) === null || _a$b$c === void 0 ? void 0 : _a$b$c.call(_a$b);
(_a2 = a) === null || _a2 === void 0 ? true : (_a2$b = _a2.b) === null || _a2$b === void 0 ? true : delete _a2$b.c;
複製代碼

細心的同窗能夠發現有幾個比較值得注意的點。

注意點

  1. babel 會在每次屬性取值時將屬性值進行緩存而不是像平時代碼中常寫的直接 a && a.b && a.b.c,這是爲了保證和原生實現的一致性,保證每一個屬性取值只會取一次,避免在一些 getter 屬性獲取時形成取值次數不一致差別性。
  2. babel 在判斷值是否爲空時並無直接使用 == null 而是使用了比較繁瑣的 === null || === void 0,這個主要是爲了兼容 document.all,關於 document.all 寫在後面。

Nullish coalescing 的轉義

a ?? b
// babel 轉義後 =====> 
"use strict";
var _a;
(_a = a) !== null && _a !== void 0 ? _a : b;
複製代碼

能夠注意到一樣是爲了兼容 document.allNullish coalescing 也使用了 === null || === void 0 來進行判斷。

document.all

document.all 是一個比較奇怪的值,它是 document 中全部元素的集合,可是它是一個假值,而且是一個特殊的空值。

document.all || 1 // 1
document.all == null // true
document.all === null // false
document.all === undefined // false
複製代碼

document.all 是一個殘留的屬性,這些特性也是爲了一些之前的兼容考慮。HTML5 中已經將它廢棄,能夠不作過多瞭解。有興趣的能夠看下 MDN Document.all 的文檔。

loose

因爲 document.all 是一個廢棄的屬性,現實開發中其實不會遇到使用的場景,既然如此咱們就不必由於一個廢棄的屬性而致使 babel 轉義出大量無心義代碼。 咱們能夠經過啓用插件的 loose 屬性來實現:

{
  "plugins": [["@babel/plugin-proposal-optional-chaining", {"loose": false}], ["@babel/plugin-proposal-nullish-coalescing-operator", {"loose": false}]]
}
複製代碼

若是是 preset-env 中集成的更簡單,直接將 preset-env 中的 loose 設爲 true 就好了。

再看下編譯的代碼:

a?.b?.[c]?.()
// babel 轉義後 =====> 
"use strict";
var _a, _a$b, _a$b$c;
(_a = a) == null ? void 0 : (_a$b = _a.b) == null ? void 0 : (_a$b$c = _a$b[c]) == null ? void 0 : _a$b$c.call(_a$b);
複製代碼
a ?? b
// babel 轉義後 =====> 
"use strict";
var _a;
(_a = a) != null ? _a : b;
複製代碼

代碼瞬間簡潔了許多。若是小心團隊有同窗誤用 document.all 也能夠在 eslint 中添加告警。

總結

Optional chainingNullish coalescing 已經歸入標準一段時間了,使用後能夠大大增長屬性獲取、默認值設置等代碼的優雅、可讀性,減小各類 Cannot read property 'foo' of undefined 的錯誤狀況。等什麼,趕忙用起來吧。

若是以爲本文有用,請不要吝嗇您的贊👍

相關文章
相關標籤/搜索