前言
本文總結了下我在前端開發過程中編寫JavaScript的一些習慣的代碼規范,以前端開發背景為主,但有些規則也適用其他語言。同時此規范並不絕對,僅供參考。
命名規范
變量長度:
變量名不要太長,盡量不超過5個單詞,若太長可以使用單詞縮寫
變量縮寫:
變量縮寫可以采用兩種縮寫方案:
1.使用單詞前幾個字母,能表述含義即可,控制在3-5個字母(具體長度自定)。如:
醫院:hosp
醫生:doc
選項:opt
2.若頁面內同時出現“文檔”和“醫生”那么doc會沖突,可以適當增加長度或變換單詞來區分。如:
文檔:docs
醫生:doct
3.使用單詞的重音字母,使人能看到字母聯想到單詞。如:
產品:pdt
配置:cfg
檢查:chk
函數命名
操作類函數:
一般使用動詞,配合各類形容詞,大致如下:
1.純動詞。如:
save()
delete()
close()
2.動詞+名詞。如:
保存醫生:saveDoc()
刪除醫院:delHosp()
創建產品:createPdt()
3.動詞+形容詞+名詞。如
刪除選中的醫生:delSelectDoc()
追加一個臨時醫院:appendTempHosp()
保存所有產品:saveAllPdt()
獲取數據類函數:
統一使用get
開頭。如:
getDocList()
getDisablePdt()
getElementById(id)
從網絡獲取數據類函數:
統一使用load
開頭。如:
獲取省份數據:loadProvince()
根據省份ID獲取市區數據:loadCityByProvinceId(pid)
根據市區ID獲取縣數據:loadCountyByCityId(cid)
load與get的區別個人認為在於,get更通用,可以用於代碼內部的數據處理邏輯,load更傾向於從遠程加載。
事件響應函數:
on+(動詞/操作)+元素+事件名。如
點擊保存按鈕:onSaveBtnClick()
點擊添加按鈕:onAddBtnClick()
當是否可用復選框變更時:onIsEnableChkChange()
頭像圖片鼠標移入時:onHeaderImgMouseEnter()
也可以是on+元素+(動詞/操作/用途)+事件名。如
onBtnSaveClick()
onChkIsEnableChange()
看個人習慣即可。
雖然看上去略繁瑣,但通過函數名本身,就可以完整的定位到此函數的用途。例如onIsEnableChkChange
函數名:
- 看到
on
開頭,知道這是一個響應界面操作事件的函數 - 看到
isEnable
,知道這是“是否可用”的功能的元素。 - 看到
chk
,知道這是一個復選框checkbox
元素的事件 - 看到末尾的
Change
,知道這是一個change
事件的響應函數 - 綜上,看到命名,就可以聯想到網頁上有一個 名叫xxx是否可用的復選框,這是點擊了這個復選框后的事件
變量命名
變量單詞連接符:
不使用單詞連接符,使用小駝峰式命名。如
btnSaveClick
布爾值類型變量:
統一使用is開頭。如
是否可用:isEnable
是否選中:isCheck
是否刪除:isDelete
集合類型變量:
統一使用List結尾。如
食品列表:foodList
醫生列表:docList
已選產品列表:selectPdtList
數組循環體內臨時變量:
若循環體代碼量少,或僅一行lambda表達式,則可簡寫 doc
或d
, pdt
或p
循環體代碼量大時,或嵌套循環時,盡量使用Item
結尾。如docItem
, pdtItem
不強制要求,僅為區分層級關系
字典變量:
統一使用Dic
(Dictionary)結尾,如
openWithDic
exeDumpDic
枚舉集合:
統一使用Enum
(Enumeration)結尾。如
醫生類型枚舉:docTypeEnum
產品狀態枚舉:pdtStatusEnum
服務器狀態碼枚舉:serverCodeEnum
枚舉項:
建議使用全大寫,使用下划線連接單詞,與常量規則一致。如
服務器返回值失敗:serverCodeEnum.ERROR
服務器返回值成功:serverCodeEnum.SUCCESS
jQuery變量:
建議使用$
開頭,或J_
開頭,風格統一即可。
$saveBtn
J_saveBtn
函數變量:
建議使用Fn
或Cb
結尾,標明此變量為函數指針。如
鈎子函數:hookFn
響應回調函數:responseCb
回調函數:callback
常量:
統一使用全大寫字母,單詞用下划線連接。如
MAX_SIZE
TIME_OUT
類(Class)構造函數:
統一使用大駝峰式命名。如
ListView
DataTable
TableView
類私有屬性:
如果未使用TypeScript
或其他強類型語言,即若沒有使用帶有訪問修飾符(public
,private
等)的語言開發,應該通過變量名本身即可區分是私有屬性還是公開屬性。
私有屬性以及私有函數,應統一以下划線開頭。如
_data
_pdtList
_getData()
_setData()
目的在於給與類的使用者可以通過變量區分,哪些是可以使用的公開屬性和方法,哪些不應該使用的私有屬性以及不應該調用的私有方法。
組件事件命名:
1.統一使用on開頭。如
onClick(e)
onSubmit(e)
2.關鍵流程類事件,應提供after事件和before事件,以onBefore和onAfter開頭。如
准備提交前事件:onBeforeSubmit
提交后事件:onAfterSubmit
准備展開前事件:onBeforeExpand
刪除后事件:onAfterDel
3.屬性/狀態變更類事件,應以on開頭,changed結尾。如
check屬性變更時事件:onCheckedChange
select屬性變更時事件:onSelectedChange
產品狀態變更時事件:onPdtStatusChange
代碼建議
- 善用變量緩存
- 重復使用多次的字符串必須緩存
- 善用枚舉變量,減少后期維護成本
- 類方法應全部掛載到原型對象
- 不應該使用類私有全局變量,應使用類靜態變量
- 盡量減少閉包代碼,以減少可能會出現的問題的概率
- 應堅持“先定義,后使用”的規范。以減少js默認的定義提升的坑
- 整個代碼應該應只有一個入口函數,即創建一個init函數,來執行所有初始代碼,而不是整篇代碼隨定義,隨執行
- 事件綁定類函數應放在同一處執行,減少維護成本
- 善用#region 創建代碼塊,不同功能的代碼歸類,初始化類,事件綁定類,界面交互類,純數據處理工具類等。
- 模塊類文件,所有導出變量應全部定義在尾部。方便查閱
- 盡可能不創建全局變量,不注冊全局事件,為后期方便轉型為單頁應用
- 盡量將代碼純數據邏輯與界面交互邏輯分開,方便后期寫測試用例
- 盡量將所有變更定義放置在 文件/函數 內頂部
- 善用try catch和throw Error
- 不要在數組內存放不同類型的數據,一個數組應只存放一種數據類型變量,方便強類型識別與糾錯
- 盡可能不要創建類數組變量
- 盡可能不使用eval、with
- 多寫注釋!推薦jsdoc風格注釋,方便一鍵抽取注釋生成代碼文檔
- 推薦使用flowjs或ts等類型描述語言來約束、規范、糾錯和智能感知。
附:關於js中的對象、字典與枚舉的關系
以上個人經驗在組內分享時,有同學提出疑問:
為什么會有字典變量,以及枚舉變量,這從本質上不都是Object對象么?
關於這個問題我是這么理解的,在js中確實對象是最強大的,任何在其他語言當中的類似對象的數據結構,在js里都可以是對象。但也正因為如此寬泛,讓我們的使用過程中會產生一些疑惑或誤解,才需要對各種的對象做分類。
所以回過頭來再說對象,字典與枚舉的關系。
他們的相同點:
他們都是鍵值對集合(KeyValuePair)
他們的Key都不能重復
他們的不同點:
對象:
對象的的Key可以是字符串類型或數值類型。如果同時包含這兩種就類數組對象,比如document.getElementBy...系列函數的返回值:HTMLCollection
,再比如HTML元素的子元素集合:NodeList
,以及HTML元素的屬性值:NamedNodeMap
,等都是類數組對象。
對象的Value的類型,可以是任意類型。而且是在一個對象變量中的Value都可以是任意類型,如JSON對象。
字典:
而字典的Key一定是字符串類型的(其他語言中不是,受限於js語言),字典的Value也可以任意類型,但在一個字典對象變量中的所有Value一定是相同類型,也就是說字典其實是個Object<string, TValue>
。
例:比如前面剛剛提到的HTML元素的attributes屬性值:NamedNodeMap
,就是應該一個典型的字典對象:它屬於Dictionary<string, Attr>
。
但是奇葩的是NamedNodeMap
也支持數組下標式訪問,所以它同時也是一個List<Attr>
,在js里只能歸結於他是類數組對象的范疇內了。

枚舉:
而最后的枚舉對象的范圍會更小,枚舉的值一般為基本數據類型,在其他語言中甚至只能是數值類型。
例如,定義一個枚舉對象用於一組常量:
// 服務器接口返回值狀態碼枚舉
var serverCodeEnum = {
SUCCESS : 0,
ERROR : 1,
XXXXX : 2,
XXXXX : 3,
}
TypeScript中的枚舉變量
在TypeScript為了照顧js語言的日常使用,把enum關鍵字的編譯后代碼做成了雙向訪問的類數組對象。
也就是既可以用過名稱獲得數值,也可以通過數值獲得名稱。使用非常方便:
【TypeScript代碼中的枚舉】
enum ownerTypeEnum {
public = 0,
private
}
【編譯為JS后的代碼】
var ownerTypeEnum;
(function (ownerTypeEnum) {
ownerTypeEnum[ownerTypeEnum["public"] = 0] = "public";
ownerTypeEnum[ownerTypeEnum["private"] = 1] = "private";
})(ownerTypeEnum || (ownerTypeEnum = {}));
// 效果:
// ownerTypeEnum.private -> 1
// ownerTypeEnum[1] -> "private"
最后
此類文章非常容易引戰,所以再次聲明以上僅個人習慣以及經驗的分享,每個人都有自己的習慣,不管采用哪種習慣其實都可以。
至少應該在組內,或是某項目內的所有成員都采用相同的一套規范,做到見名知意。