数据字段防卫探索
- 2019 年 12 月 4 日
- 筆記
本文作者:IMWeb 黎清龙 原文出处:IMWeb社区 未经同意,禁止转载
数据字段防卫探索
这个标题不知道怎么取,估计没人看得懂,还是直接看背景吧 -_-!!
背景
某天,小Y借到一个需求:页面这里要展示一个列表,cgi数据字段是xxxlist
太简单了,几分钟的事情:
DB.getData({ // ... succ: function(data) { for (var i = 0, l = data.result.xxxlist.length; i < l; ++i) { showItem(data.result.xxxlist[i]); } } });
自测,免测发布,完美!
但是,没过多久,客服接到一堆的用户投诉,xxx页面打开白屏!
小Y吓了一跳,怎么可能,刚刚那个代码那么简单,绝对不会出错的!
用用户投诉的页面,打开控制台一看:
发现报了一个错:

排查之后发现,原因是data.result.xxxlist
是undefined
顿时一万匹草泥马在心里奔腾而过,不是说好是个列表吗,没有列表应该返回[]
呀
没办法,小Y只能紧急修复代码:
DB.getData({ // ... succ: function(data) { if (data && data.result && data.result.xxxlist) { for (var i = 0, l = data.result.xxxlist.length; i < l; ++i) { showItem(data.result.xxxlist[i]); } } } });
分析
上面的背景案例中,小Y忽略了一个很重要的原则:
永远不要相信输入!
还记得老师曾经这样教导我们:
在编写函数的时候,一定要检测参数是否合理
对于前端来说,cgi数据也是一样的,永远不能相信cgi传过来的数据
!
有人会说,这只是小Y不够严谨,当需要用某些字段的时候,就应该先检测
那就又疏忽了,人也是不可信的,当bugfix很紧急的时候还记得吗?别人写的代码能控制吗?再细心的人也会有疏忽的时候
另外,如果都加上防卫代码的时候,代码可能会长成这样:
DB.getData({ // ... succ: function(data) { if (!data) return; if (!data.a) return; if (data.b) { // ... } if (data.c) { // ... } if (data.d && data.d.e) { // ... } // 你就一直if下去吧,我不拦你! } });
通过背景案例以及分析,现在终于可以解释数据字段防卫
是什么东东了
在访问
object.key
时,防止object
可能是undefined或者null时抛错
方案
对于这个问题,这里抛几个方案,希望可以引出各位读者的玉!
方案一:抽象cgi数据
类似orm那样,预先定义model(cgi数据)的schema,如果定义了schema,那我们就可以添加默认值机制
了
这个方案的本质就是对cgi数据添加了一层加工层,让cgi数据变得可信
优点:抽象cgi数据不仅可以做数据字段防卫,还可以做很多事情 缺点:太重,毫无疑问的
方案二:重定义undefined
比如我们可以这样:
window.undefined = { length: 0 };
优点:简单 缺点:某些浏览器不支持,见下图;typeof 会出问题

在浏览器不支持的情况下,这个方案可以被枪毙了 -_-!!
方案三:封装获取数据字段的接口
获取数据字段不是原生的object.key,而是util.get(object, key),在get方法里面进行防卫处理
优点:实现统一简单 缺点:改变了原来的编程习惯;原有代码需要改动
方案四:让工具帮你
让工具透明的解决这个问题,直接看例子吧
function test(obj) { var T; T = require('tools'); var name = T.cookie.get('name'); if (!obj) { obj = { count: { count: 5 } }; } obj.count.count = 6; }
经过工具之后:
function test(obj) { var T; T = require('tools'); T.cookie= T.cookie|| T.cookie=== '' ? T.cookie: {}; var name = T.cookie.get('name'); if (!obj) { obj = { count: { count: 5 } }; } obj.count = obj.count || obj.count === '' ? obj.count : {}; obj.count.count = 6; }
通过工具保证,在访问object.key之前,object不会是undefined或者是null
优点:透明 缺点:依赖工具的智能与强大;会添加一些多余代码(因为工具无法识别哪些变量才是真正需要的)
感兴趣的话可以看下作者编写的工具data-member-defender
该工具还需要完善,欢迎提 issue !