場景
我們在開發過程當中,總是會遇到因為數據原因,導致使用數組方法或者獲取對象屬性的時候報錯。
xxx is not fuction
Cannot read property xxxx of undefined
因為這些錯誤,會導致直接頁面打不開,所以我們一般會做一些容錯處理,從而讓頁面可以正常打開。例如:&& 、三元運算符,甚至有時會看到 if 語句來處理。
常見方式
1 // response 是來自接口的數據 2 const response = { 3 code: 200, 4 msg: 'message', 5 data: { 6 total: 100, 7 page: 1, 8 pageSize: 10, 9 content: [] 10 } 11 } 12 13 const goodsList = response.data.content.forEach(() => {}) 14 const total = response.data.total
為了保證取data、content屬性和使用forEach不報錯,可能會這樣做
1 const goodsList = response.data && response.data.content && response.data.content.forEach(() => {}) 2 const total = response.data && response.data.total
這樣就初步完成了數據容錯,但是代碼過於冗余可讀性差,而且 total 的值還會可能變成 Boolean 類型。
簡單改進
只需要簡單的兩個處理,一個是解構,一個是給默認值
1 const { data = {} } = response 2 const { constent = [], total = [] } = data 3 goodsList.forEach(() => {})
解構是非常有必要的,增加代碼可讀性和扁平化數據
不過,但這里又有了新的問題。這個時候如果我得到數據如下的樣子:
1 const response = { 2 data: null 3 }
那么解構就會報錯 Cannot destructure property content
of 'undefined' or 'null'
默認值生效的條件是,對象的屬性值嚴格等於undefined
上面代碼中,屬性data等於null,因為null與undefined不嚴格相等,所以是個有效的賦值,導致默認值 {} 不會生效。實際就成了如下的樣子:
1 const { constent = [], total = [] } = null
因此我們得保證拿到的數據不能存在null,不然上面的代碼就沒意義了。
進一步改進
你可能在想和后端約定好不返回 null 就好了
但是不能過分相信外部數據,包括約定之后的
這種情況其實可以在封裝axios 或者fetch的時候,在里面添加一個過濾的函數,把從接口拿到的數據過濾一下,過濾掉值為 null 的數據,或者是把為 null 的數據重新賦值為 undefined。
下面是過濾數據的函數
1 // 把獲取到的數據過濾一遍 2 const replaceNull = (obj) => { 3 for (let key in obj) { 4 switch (Object.prototype.toString.call(obj[key]).slice(8, -1)) { 5 case 'Object': 6 replaceNull(obj[key]) 7 break; 8 case 'Array': 9 for (let i = 0; i < obj[key].length; i++){ 10 replaceNull(obj[key][i]) 11 } 12 break; 13 default: 14 if (obj[key] === null) obj[key] = undefined; 15 } 16 } 17 }
過濾之后,這個時候這種寫法就沒問題了
1 const { data = {} } = response 2 const { constent = [], total = [] } = data 3 goodsList.forEach(() => {})
當然如果你們有node作為中間層,前端視圖層是可以放心的使用解構默認值的,比如 graphQl 這種。
結束語
前端數據容錯處理是必須的,不能期待外部數據的格式就是自己想要的。不知道大家平時都是怎么處理的。