场景
我们在开发过程当中,总是会遇到因为数据原因,导致使用数组方法或者获取对象属性的时候报错。
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 这种。
结束语
前端数据容错处理是必须的,不能期待外部数据的格式就是自己想要的。不知道大家平时都是怎么处理的。
















