JS中的空值


盡管從第一次遇到空值引起的bug開始,我就一直要求自己注意空值,但還是經常犯這樣的錯誤,js中的空值真的需要多加注意。這里說的空值包括undefined和null

 

為什么js容易出現空值bug?

首先JS是一個動態類型語言,與之相對的是靜態類型語言如Java。在Java中要定義數據模型意味着定義一個類——JavaBean,無論這個數據模型的結構多么簡單。在JS中就簡單的多:

var auth = {
  visible: true, editable: true } 

這種靈活的方式帶來了很大的便捷,但這種便捷是有代價的。JS並不能保證所有的auth對象是同樣的結構,auth.visible並不一定是布爾型,有可能是undefined或者其它類型的數據。盡管定義一個JavaBean有些麻煩,Java中不會出現這樣的情況——你可以確定一個auth對象一定有一個布爾型的visible屬性。

 

空值bug會以哪些形式出現?

有的時候定義數據時會默認{}或者undefined就是{visible: false, enbale: false},或者{name: 'afei'}就是{name: 'afei': phone: ''}。在使用數據時很容易遺漏這種隱藏邏輯,從而引發bug。而且這種空值只在少部分情況下出現,很容易躲過測試。

function fn (obj) { console.log(obj[key].id); }

這里obj或者obj[key]為空都會導致報錯。

function fn (authArray) { authArray.forEach(function (i, auth) { console.log(auth.visible); }) }

這種形式就更具迷惑性,你很容易就覺得authArray里面肯定都是auth吧,既然是auth肯定有visible屬性吧。然而並沒有人能保證這一點,authArray里面可能有別的數據:空值或者沒有visible屬性的auth對象。

function fn (authIdArray, authMap) { authIdArray.forEach(function (i, authId) { var auth = authMap[authId]; console.log(auth.visible); }) }

同樣,看到authIdArray和authMap,很容易覺得它們一定是一一對應的,應該可以取到一個auth對象。

總而言之,JS並不能保證數據的結構化,而開發過程中很容易默認取到的是結構化數據。

 

怎么解決

遇到空值bug有兩種解決方案。

在取值的地方加判斷

function fn (auth) { var val = obj[key]; if (val) { console.log(val.id); } }

還有一種寫法:

function fn (obj) { console.log(obj[key] && obj[key].id); }

在變量聲明和賦值的地方保證數據結構一致

var auth = { visible: booleanVal || false } authArray.push(authObj || {}); authMap[id] = authObj || {};

如果auth的某個屬性還不是基礎類型,可能更麻煩一些——不能用{}來代替auth。

第一種方法改動起來更簡單,但是第二種方法能保持數據結構一致,有利於代碼的長期維護。一種比較中庸的方法是:在私有方法中聲明和賦值時保證數據的結構一致,在公共方法中接收的變量則檢查數據結構(JS不區分公共和私有方法,一個約定俗成的做法是私有方法加上下划線前綴)。

廣州品牌設計公司https://www.houdianzi.com PPT模板下載大全https://redbox.wode007.com

從TypeScript得到的啟示

TypeScript是一種由微軟開發的自由和開源的編程語言。它是JavaScript的一個嚴格超集,並添加了可選的靜態類型和基於類的面向對象編程。所謂可選的靜態類型可以理解為靈活范式——本來是無范式的。TypeScript可以聲明參數或屬性的數據類型,在編譯時進行類型檢查,也可以通過any類型來跳過類型檢查。 使用TypeScript后IDE的補全和跳轉可以像靜態語言一樣,對開發者更加友好,數據類型引起的bug也會大大減少。從使用者評價來看,大型項目中使用TypeScript有助於提高開發效率和減少bug。

fx-code工程引入TypeScript的障礙有兩點:一是工程中沒有實現模塊化而是AllInOne模式,不能在一個組件中引入另外一個組件,TypeScript也就沒辦法發揮作用。二是遺留代碼需要編寫大量的聲明文件,而且需要開發者轉換靜態類型語言的思維。

在引入之前或者不引入的話,我們也可以通過注釋來起到申明數據類型的作用。

/** * @param fields {Array<Field>} * @interface * Field { * name: string, * text: string, * enbale: boolean | undefined, * layout: 6 | 12 * } * @return void */ function fn (fields, fieldAuth) { // ... } 

對於可能為undefined和{}的變量的注釋尤其要詳細。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM