實務上我們常需要讀取 Object 的 Property,但我們並不確定 Object 是否有該 Property,最嚴謹的做法必須先檢查 Property 是否存在才能讀取,否則在 Runtime 可能會得到 Cannot read property xxx of undefined
的錯誤訊息。
Version
macOS Mojave 10.14.5
VS Code 1.36.1
Quokka 1.0.240
Ramda 0.26.1
Functional
import { defaultTo, path } from 'ramda';
let pathOr = val => arr => obj => defaultTo(val, path(arr, obj));
let usrFn = pathOr('No name')(['student', 'name']);
usrFn({}); // ?
usrFn({ student1: { name: 'Sam' } }); // ?
usrFn({ student: { name1: 'Sam' } }); // ?
usrFn({ student: { name: 'Sam' } }); // ?
若 object 具有 nested property,而我們又想讀取 object.student.name
的值。
由於 ECMAScript 是 dynamic language,並不保證 object 具有 student
與 name
property,若只是 let usrFn = obj => obj.student.name;
,只要傳入的 object 沒有 student
與 name
property,在 runtime 就會出現 Cannot read property xxx of undefined
的錯誤訊息。
實作 pathOr()
,第一個 argument 傳入 default value,第二個 argument 傳入 property 名稱 array,第三個 argument 傳入 object,最後使用 &&
對每一層 property 做檢查,最後在加上 ||
提供 default value。
Ramda
import { pathOr } from 'ramda';
let usrFn = pathOr('No name', ['student', 'name']);
usrFn({}); // ?
usrFn({ student1: { name: 'Sam' } }); // ?
usrFn({ student: { name1: 'Sam' } }); // ?
usrFn({ student: { name: 'Sam' } }); // ?
事實上 Ramda 已經提供 pathOr()
,可直接使用。
pathOr()
a -> [Idx] -> {a} -> a
Idx = String | Int
針對 object 的 nested property 取值,若 property 不存在,則回傳 default value
a
:若 nested property 不存在,則提供 default value 回傳
[Idx]
:以 array 描述 nested property
{a}
:data 為 object
a
:回傳 property 的 value 或 default value
pathOr()
寫法遠比 &&
與 ||
語意更清楚,也不用擔心會少寫一層 propery 沒檢查。
Conclusion
- 由於 ECMAScript 是 dynamic language,因此很多都必須在 runtime 檢查
- 若要讀取 object 的 property,對於 property 的檢查是必要的,因為無法確定該 object 是否有 property,建議使用 Ramda 的
propOr()
與pathOr()
取代用&&
與||
檢查,不只語意更清楚,還可避免 property 檢查不完全