Week8 - 不想再看到undefined的TypeError吗,你可以试看看JS的Optional chaining

爆炸的起因

在实务上,我们常常会碰到「把得到的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为namevalue是不是等于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')

是不是让人想起了一首名叫洋葱的歌


解决此问题的救星 - Optional chaining operator

为了解决此问题,在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?来说,会有以下两种情形

如果rows存在就继续往下查找[0],如果rows不存在就直接回传undefine,并且不会再继续往下查找[0]

这真的很方便,在MDN有更多的使用情境,但都是与此情境相似,大家可以参考看看

这真的好酷,那我试看看在Node.js,shit...爆炸了

刚刚有提到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这个恶梦,欢迎大家分享,也欢迎指正文章,谢谢~


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章