type
Post
status
Published
date
Mar 6, 2020
slug
summary
可选链式调用与空值合并运算符
tags
ECMAScript
JavaScript
category
技术分享
icon
password
可选链式调用与空值合并运算符

正常返回的数据结构

const interfaceList = [ { id: 1104, name: 'onlinemq1:tp_mdm_user:broker-dev:1', data: { avgRt: 75.48, avgRtComparePrev: '-19.28%', hitCount: 42, }, }, { id: 1102, name: 'ymmoa:oabbsService_1.0.0:selectValidChildrenBlocks()', data: { avgRt: 13.34, avgRtComparePrev: '39.92%', hitCount: 116, }, }, ];
然后我们就这样写了
{ interfaceList.map(inter => ( <div key={inter.id}> <div>接口名:{inter.name}</div> <div>请求量:{inter.data.hitCount}</div> <div>平均响应时间:{inter.data.avgRt}</div> <div>平均RT环比昨日:{inter.data.avgRtComparePrev}</div> </div> )); }

异常非正常返回的数据结构

const interfaceList = [ { // 情况 1 id: 1101, name: 'onlinemq1:tp_mdm_user:broker-dev:1', data: { avgRt: 0, avgRtComparePrev: '0.00%', hitCount: 0, }, }, { // 情况 2 id: 1102, name: 'ymmoa:oabbsService_1.0.0:selectValidChildrenBlocks()', data: { avgRt: null, avgRtComparePrev: '', hitCount: null, }, }, { // 情况 3 id: 1102, name: '/cat/r/p', data: {}, }, { // 情况 4 id: 1102, name: '/cat/r/p', data: null, }, { // 情况 5 id: 1102, name: '/cat/r/p', }, ]; const interfaceList = null; // 情况6

问题开始暴露

// 情况 1 暂时没问题 // 情况 2 空白 // 情况 3 空白 // 情况 4 ❌ Uncaught TypeError: Cannot read property 'XXX' of null // 情况 5 ❌ Uncaught TypeError: Cannot read property 'XXX' of undefined { interfaceList.map(inter => ( <div key={inter.id}> <div>接口名:{inter.name}</div> <div>请求量:{inter.data.hitCount}</div> <div>平均响应时间:{inter.data.avgRt}</div> <div>平均RT环比昨日:{inter.data.avgRtComparePrev}</div> </div> )); }

展示’-’,表示暂无数据

// 情况 1 ❌ 数据为 0 也成了暂无数据 // 情况 2 暂时没问题 // 情况 3 暂时没问题 // 情况 4 ❌ Uncaught TypeError: Cannot read property 'XXX' of null // 情况 5 ❌ Uncaught TypeError: Cannot read property 'XXX' of undefined { interfaceList.map(inter => ( <div key={inter.id}> <div>接口名:{inter.name}</div> <div>请求量:{inter.data.hitCount || '-'}</div> <div>平均响应时间:{inter.data.avgRt || '-'}</div> <div>平均RT环比昨日:{inter.data.avgRtComparePrev || '-'}</div> </div> )); }

解决情况 1、4、5

// 情况 1 暂时没问题 // 情况 2 ❌ avgRtComparePrev 是 '' 表示没数据 // 情况 3 暂时没问题 // 情况 4 暂时没问题 // 情况 5 暂时没问题 { interfaceList.map(inter => ( <div key={inter.id}> <div>接口名:{inter.name}</div> <div> 请求量: {inter.data !== null && inter.data !== undefined && inter.data.hitCount !== null && inter.data.hitCount !== undefined ? inter.data.hitCount : '-'} </div> <div> 平均响应时间: {inter.data !== null && inter.data !== undefined && inter.data.avgRt !== null && inter.data.avgRt !== undefined ? inter.data.avgRt : '-'} </div> <div> 平均RT环比昨日: {inter.data !== null && inter.data !== undefined && inter.data.avgRtComparePrev !== null && inter.data.avgRtComparePrev !== undefined ? inter.data.avgRtComparePrev : '-'} </div> </div> )); }

优化

// 情况 1 没问题 // 情况 2 没问题 // 情况 3 没问题 // 情况 4 没问题 // 情况 5 没问题 { interfaceList.map(inter => ( <div key={inter.id}> <div>接口名:{inter.name}</div> <div> 请求量: {inter.data !== null && inter.data !== undefined && inter.data.hitCount !== null && inter.data.hitCount !== undefined ? inter.data.hitCount : '-'} </div> <div> 平均响应时间: {inter.data !== null && inter.data !== undefined && inter.data.avgRt !== null && inter.data.avgRt !== undefined ? inter.data.avgRt : '-'} </div> <div> 平均RT环比昨日: {inter.data !== null && inter.data !== undefined && inter.data.avgRtComparePrev ? inter.data.avgRtComparePrev : '-'} </div> </div> )); }

再优化

{ interfaceList.map(inter => ( <div key={inter.id}> <div>接口名:{inter.name}</div> <div> 请求量: {!_.isNil(inter.data) && !_.isNil(inter.data.hitCount) ? inter.data.hitCount : '-'} </div> <div> 平均响应时间: {!_.isNil(inter.data) && !_.isNil(inter.data.avgRt) ? inter.data.avgRt : '-'} </div> <div> 平均RT环比昨日: {!_.isNil(inter.data) && inter.data.avgRtComparePrev ? inter.data.avgRtComparePrev : '-'} </div> </div> )); }

既然都用了 lodash

{ interfaceList.map(inter => { // 不推荐使用 get 的第三个参数设置默认值,因为只有在 undefined 的时候才会设置,null 被认为是有值的 const hitCount = _.get(inter, 'data.hitCount'); const avgRt = _.get(inter, 'data.avgRt'); const avgRtComparePrev = _.get(inter, 'data.avgRtComparePrev'); return ( <div key={inter.id}> <div>接口名:{inter.name}</div> <div> 请求量: {!_.isNil(hitCount) ? hitCount : '-'} </div> <div> 平均响应时间: {!_.isNil(avgRt) ? avgRt : '-'} </div> <div> 平均RT环比昨日: {avgRtComparePrev || '-'} </div> </div> ); }); }

用 optional chain 替换掉 _.get()

// 情况 1 暂时没问题 // 情况 2 暂时没问题 // 情况 3 暂时没问题 // 情况 4 暂时没问题 // 情况 5 暂时没问题 { interfaceList.map(inter => ( <div key={inter.id}> <div>接口名:{inter.name}</div> <div> 请求量: {!_.isNil(inter.data?.hitCount) ? inter.data?.hitCount : '-'} </div> <div> 平均响应时间: {!_.isNil(inter.data?.avgRt) ? inter.data?.avgRt : '-'} </div> <div> 平均RT环比昨日: {inter.data?.avgRtComparePrev || '-'} </div> </div> )); }

用 nullish coalescing operator 替换掉 _.isNill

// 情况 1 暂时没问题 // 情况 2 暂时没问题 // 情况 3 暂时没问题 // 情况 4 暂时没问题 // 情况 5 暂时没问题 { interfaceList.map(inter => ( <div key={inter.id}> <div>接口名:{inter.name}</div> <div> 请求量: {inter.data?.hitCount ?? '-'} </div> <div> 平均响应时间: {inter.data?.avgRt ?? '-'} </div> <div> 平均RT环比昨日: {inter.data?.avgRtComparePrev || '-'} </div> </div> )); }

情况 6 来了

{ interfaceList?.map(inter => ( <div key={inter.id}> <div>接口名:{inter.name}</div> <div> 请求量: {inter.data?.hitCount ?? '-'} </div> <div> 平均响应时间: {inter.data?.avgRt ?? '-'} </div> <div> 平均RT环比昨日: {inter.data?.avgRtComparePrev || '-'} </div> </div> )); }

这么爽!我能用了吗?

  • TypeScript 3.7 supports Optional Chaining & Nullish Coalescing
  • Babel 7.8.0 supports Optional Chaining & Nullish Coalescing
  • @babel/proposal-optional-chaining,
  • @babel/proposal-nullish-coalescing-operator
ESLint ChecklistReact Hooks