數據欄位防衛探索
- 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 !
