面臨的問題
假設有這樣一個物件,表示的是 使用者是否啟用了回覆通知的設定
const settings = {
notification: {
reply: {
active: {
true
}
}
// ...其他設定項
}
// ...其他設定項
}
複製程式碼
當開發者想要提取 active
的值,最直接的方法是這麼做
const isNotificationReplyActive = settings.notification.reply.active
複製程式碼
但這是不安全的,因為 JavaScript 中通常使用 null
或 undefined
分別表示未定義或未宣告的值
typeof someVar === 'undefined' // 未宣告
let someVar = null // 已宣告,未定義
複製程式碼
實際開發過程中可能因為比如節省資源的考慮,當使用者未進行過設定時,它的 notification 或者更深的某一級的值是 null
或 undefined
,而非物件。
// 比如當未設定回覆通知時,它是這樣的
const settings = {
notification: {
// 沒有 reply
}
}
// 這種情況下, settings.notification.reply 的值是 undefined
// JS 中試圖獲取 undefined 上的 key 時會觸發 TypeError
const isNotificationReplyActive = settings.notification.reply.active // TypeError!
複製程式碼
於是開發者採取了這樣的措施
const isNotificationReplyActive = settings
&& settings.notification
&& settings.notification.reply
&& settings.notification.reply.active
// 或者
try {
const isNotificationReplyActive = settings.notification.reply.active
} catch (err) {
// 錯誤處理
}
複製程式碼
經驗豐富的開發者都知道,這樣做的缺點很多,在此就不展開了。
於是一些工具函式誕生了,比如 lodash 的 _.get
import _ from 'lodash'
const isNotificationReplyActive = _.get(settings, 'notification.reply.active')
複製程式碼
雖然它保證了開發者在提取屬性的過程中不會因為遇到 undefined
或 null
之類的值而丟擲 TypeError ,但缺點也很明顯——
- 屬性的路徑被寫成了字串,開發者無法獲得 IDE/編輯器 的自動補全與智慧糾錯。
- 不能使用便捷的解構語法——
const { notification: { reply: { active } } } = settings
簡直是一夜回到解放前。
解決方法 —— safe-touch
現在讓我們來回顧一下本文開頭的那張圖——它即是本文的主角、上述所有問題的解決方案。
// 引入
import safeTouch from 'safe-touch'
const settings = { /* ... */ }
// 包裹要提取的物件
const touched = safeTouch(settings)
// 把它當作函式呼叫,可以獲得原始值
touched() === settings // true
// 亦可以直接獲取 settings 上存在的屬性,同樣通過呼叫取得屬性值
// 在現代化的 IDE/編輯器 中,這一過程可以給出智慧提示與自動補全
touched.notification.reply.active() // 若依本文開頭給出的例子,值為 true
// 可以安全地獲取並不存在的屬性,返回 undefined ,不會丟擲 TypeError
touched.something.does.not.exist[Math.random()]() // undefined
// 支援解構
const { notification: { reply: { active, notExistingKey } } } = touched
active() // true
notExistingKey() // undefined
複製程式碼
怎麼做到的
其實不難,核心功能通過 ES6 的 Proxy 就可以實現。再結合 TypeScript 的型別判斷(初學 TS,看了好久文件),生成 index.d.ts 供智慧化的 IDE/編輯器 使用,就有了自動補全與智慧提示。
短小的原始碼 repo (歡迎 Star / issue)