在實務上,我們常常會碰到「把得到的response做分析,並產生對應行為的」情境,如下展示為從DB拿回各個人名的資料:
const response = {
rows: [
{
name: 'John'
}
]
}
if (response.rows[0].name === 'John') console.log('Get John')
我們可以發現,response裡面的rows其實是「不太確定」的,如果John在DB被刪除了,就會得到以下response:
const response = {
rows: []
}
if (response.rows[0].name === 'John') console.log('Get John')
這樣會導致程式碼直接錯誤:
"TypeError: Cannot read property 'name' of undefined
因為在解析response.rows[0]
得到的已經是undefined
,這時我們再從undefined
裡面取出key為name
的value時,就會直接爆炸\( `.∀´)/。
我們可以將程式碼改成如下:
const response = {
rows: []
}
if (response.rows[0] && response.rows[0].name === 'John') console.log('Get John')
這樣的做法是先檢查response.rows[0]
存不存在,如果存在再繼續檢查內部key為name
的value
是不是等於John
,這樣的方法的確解決了我們的問題。
但如果John的資料越來越多,形成了巢狀object,而我們的情境變為「解析John使用的飛機交通工具是不是Brt707
時」,就會變成這樣:
const response = {
rows: [
{
"name": "John",
"age": 28,
"vehicles": {
"car": "Suzuki",
"bike": "Ubike",
"airlines":{
"UNI AIR" : "Air123",
"Mandarin" : "Brt707"
}
}
}
]
}
if (
response.rows[0] &&
response.rows[0].vehicles &&
response.rows[0].vehicles.airlines &&
response.rows[0].vehicles.airlines.Mandarin === 'Brt707'
) console.log('Get Brt707')
是不是讓人想起了一首名叫洋蔥的歌
為了解決此問題,在TC39(就是制定許多新語法的協會)有了此項新提案,目前已經進入stage4(如果不太清楚stage可以看此篇文章),在Chrome裡面已經可以使用,這邊直接舉例講解:
const response = {
rows: [
{
"name": "John",
"age": 28,
"vehicles": {
"car": "Suzuki",
"bike": "Ubike",
"airlines":{
"UNI AIR" : "Air123",
"Mandarin" : "Brt707"
}
}
}
]
}
if (response.rows?.[0]?.vehicles?.airlines?.Mandarin === 'Brt707') console.log('Get Brt707')
以rows?來說,會有以下兩種情形
這真的很方便,在MDN有更多的使用情境,但都是與此情境相似,大家可以參考看看
剛剛有提到MDN,我們就來看看MDN下方所提供的support表:
是的,Node.js目前並不支援此用法,但沒關係,我們有Babel.js plugin的幫忙!可以提前使用它,
這個Babel.js就是我們可以使用新版的一些特性,而Babel.js會幫我們把code轉成舊版的code,讓Node.js可以讀懂他
有,我們可以用lodash的get,如果找不到值會回傳undefine
const _ = require('lodash')
const response = {
rows: [
{
"name": "John",
"age": 28,
"vehicles": {
"car": "Suzuki",
"bike": "Ubike",
"airlines":{
"UNI AIR" : "Air123",
"Mandarin" : "Brt707"
}
}
}
]
}
if (_.get(response, 'rows.[0].vehicles.airlines.Mandarin') === 'Brt707') console.log('Get Brt707')
jsonpath的query,找不到值會回傳空array。此種方法是json的一種路徑方法,在許多語言都有支持,例如java也擁有jsonpath,
const jp = require('jsonpath');
const response = {
rows: [
{
"name": "John",
"age": 28,
"vehicles": {
"car": "Suzuki",
"bike": "Ubike",
"airlines":{
"UNI AIR" : "Air123",
"Mandarin" : "Brt707"
}
}
}
]
}
if (jp.query(response, '$.rows[0].vehicles.airlines.Mandarin')[0] === 'Brt707') console.log('Get Brt707')
最後我是選擇lodash的get來找尋這些value,主要是因為後端專案要透過Bable.js編譯雖然不需要太多時間,但眾多專案一起來,我的時間就噴了(`Д´*)。
但我非常期待Optional chaining operatory在Node.js原生支持的一天,此方法使用起來非常的順手與漂亮。
你是喜歡哪種方法,或者還有什麼方法可以解決undefine這個惡夢,歡迎大家分享,也歡迎指正文章,謝謝~
哦哦哦哦~
剛好最近碰到類似的問題
還用了一大堆if去防止噴錯
原來還有這種寫法
能幫到忙非常開心,哈哈,
不過要注意這方法目前最支援的是前端,
後端需要透過babel之類,就如文章所說~