方才在程序里看到一段JS代碼辑甜,寫法極為高明,私心想著若是其按照規(guī)范來寫袍冷,定可培養(yǎng)對這門語言的理解磷醋,對JS編程能力提高必是極好的。說人話:丫代碼寫的太亂胡诗,看的窩火邓线!
最近閑暇無事,準備對自己JS學習做一個總結煌恢。眾所周知骇陈,JS是一種語法極其靈活的語言,一千個人會有一千種JS書寫方式瑰抵。這造成的結果往往就是給項目日后的開發(fā)及維護留下一個不小的隱患你雌,也對你和團隊再次開發(fā)及閱讀代碼造成一定困難,個人認為良好的書寫規(guī)范是應該首當其沖的二汛。所以參考一些優(yōu)秀前端開發(fā)團隊的代碼規(guī)范后婿崭,總結了幾點,希望能讓你的Javascript代碼上升一個臺階习贫。
變量命名
變量名包括全局變量逛球,局部變量,類變量苫昌,函數(shù)參數(shù)等等颤绕,他們都屬于這一類幸海。
變量命名都以類型前綴+有意義的單詞組成,用駝峰式命名法增加變量和函式的可讀性奥务。例如:sUserName物独,nCount。
前綴規(guī)范
每個局部變量都需要有一個類型前綴氯葬,按照類型可以分為:
s:表示字符串挡篓。例如:sName,sHtml帚称;
n:表示數(shù)字官研。例如:nPage,nTotal闯睹;
b:表示邏輯戏羽。例如:bChecked,bHasLogin楼吃;
a:表示數(shù)組始花。例如:aList,aGroup孩锡;
r:表示正則表達式酷宵。例如:rDomain,rEmail躬窜;
f:表示函數(shù)浇垦。例如:fGetHtml,fInit斩披;
o:表示以上未涉及到的其他對象溜族,例如:oButton,oDate垦沉;
g:表示全局變量煌抒,例如:gUserName,gLoginTime厕倍;
當然寡壮,也可以根據(jù)團隊及項目需要增加前綴規(guī)范,例如我們團隊會用到:
$:表示Jquery對象讹弯。例如:$Content况既,$Module;
一種比較廣泛的Jquery對象變量命名規(guī)范组民。
j:表示Jquery對象棒仍。例如:jContent, jModule臭胜;
另一種Jquery對象變量命名方式莫其。
fn:表示函數(shù)癞尚。例如:fnGetName,fnSetAge乱陡;
和上面函數(shù)的前綴略有不同浇揩,改用fn來代替,個人認為fn能夠更好的區(qū)分普通變量和函數(shù)變量憨颠。
dom:表示Dom對象胳徽,例如:domForm,domInput爽彤;
項目中很多地方會用到原生的Dom方法及屬性养盗,可以根據(jù)團隊需要適當修改。
這里可以根據(jù)項目及團隊需要适篙,設計出針對項目需要的前綴規(guī)范爪瓜,從而達到團隊開發(fā)協(xié)作便利的目的。
例外情況
作用域不大臨時變量可以簡寫匙瘪,比如:str,num蝶缀,bol丹喻,obj,fun翁都,arr碍论。
循環(huán)變量可以簡寫,比如:i柄慰,j鳍悠,k等。
某些作為不允許修改值的變量認為是常量坐搔,全部字母都大寫藏研。例如:COPYRIGHT,PI概行。常量可以存在于函數(shù)中蠢挡,也可以存在于全局。
為什么需要這樣強制定義變量前綴凳忙?正式因為javascript是弱語言造成的业踏。在定義大量變量的時候,我們需要很明確的知道當前變量是什么屬性涧卵,如果只通過普通單詞勤家,是很難區(qū)分的。
//普通代碼
var checked = false;
var check = function() {
return true;
}
/**
some code
**/
if(check) {//已經無法很確切知道這里是要用checked還是check()從而導致邏輯錯誤
//do some thing
}
//規(guī)范后代碼
var bChecked = false;
var fnCheck = function() {
return true;
}
/**
some code
**/
if(bChecked) {
// do some thing
}
if(fnCheck()) {
// do other thing
}
函數(shù)命名
統(tǒng)一使用動詞或者動詞+名詞形式柳恐,例如:fnGetVersion()伐脖,fnSubmitForm()热幔,fnInit();涉及返回邏輯值的函數(shù)可以使用is晓殊,has断凶,contains等表示邏輯的詞語代替動詞,例如:fnIsObject()巫俺,fnHasClass()认烁,fnContainsElment()。
如果有內部函數(shù)介汹,使用_fn+動詞+名詞形式却嗡,內部函數(shù)必需在函數(shù)最后定義。例如:
function fnGetNumber(nTotal) {
if (nTotal < 100) {
nTotal = 100;
}
return _fnAdd(nTotal);
function _fnAdd(nNumber) {
nNumber++;
return nNumber;
}
}
alert(fGetNumber(10)); //alert 101
對象方法與事件響應函數(shù)
對象方法命名使用fn+對象類名+動詞+名詞形式嘹承;例如 fnAddressGetEmail()窗价,主觀覺得加上對象類名略有些雞肋,個人認為一個對象公開的屬性與方法應該做到簡潔易讀叹卷。多增加一個對象類名單詞撼港,看著統(tǒng)一了,但有點為了規(guī)范而規(guī)范的味道骤竹,這里根據(jù)自身喜好仁者見仁智者見智吧帝牡。
某事件響應函數(shù)命名方式為fn+觸發(fā)事件對象名+事件名或者模塊名,例如:fnDivClick()蒙揣,fnAddressSubmitButtonClick()
補充一些函數(shù)方法常用的動詞
get 獲取/set 設置, add 增加/remove 刪除
create 創(chuàng)建/destory 移除 start 啟動/stop 停止
open 打開/close 關閉, read 讀取/write 寫入
load 載入/save 保存, create 創(chuàng)建/destroy 銷毀
begin 開始/end 結束, backup 備份/restore 恢復
import 導入/export 導出, split 分割/merge 合并
inject 注入/extract 提取, attach 附著/detach 脫離
bind 綁定/separate 分離, view 查看/browse 瀏覽
edit 編輯/modify 修改, select 選取/mark 標記
copy 復制/paste 粘貼, undo 撤銷/redo 重做
insert 插入/delete 移除, add 加入/append 添加
clean 清理/clear 清除, index 索引/sort 排序
find 查找/search 搜索, increase 增加/decrease 減少
play 播放/pause 暫停, launch 啟動/run 運行
compile 編譯/execute 執(zhí)行, debug 調試/trace 跟蹤
observe 觀察/listen 監(jiān)聽, build 構建/publish 發(fā)布
input 輸入/output 輸出, encode 編碼/decode 解碼
encrypt 加密/decrypt 解密, compress 壓縮/decompress 解壓縮
pack 打包/unpack 解包, parse 解析/emit 生成
connect 連接/disconnect 斷開, send 發(fā)送/receive 接收
download 下載/upload 上傳, refresh 刷新/synchronize 同步
update 更新/revert 復原, lock 鎖定/unlock 解鎖
check out 簽出/check in 簽入, submit 提交/commit 交付
push 推/pull 拉, expand 展開/collapse 折疊
begin 起始/end 結束, start 開始/finish 完成
enter 進入/exit 退出, abort 放棄/quit 離開
obsolete 廢棄/depreciate 廢舊, collect 收集/aggregate 聚集
上面討論了基本的JS書寫命名規(guī)范靶溜,按我個人看法,只要能夠按照上面的規(guī)范寫出來的代碼懒震,一般不會太糟糕罩息,最不濟沒人會說你代碼亂的難以閱讀。代碼規(guī)范對于大團隊的維護建設是毋庸置疑的个扰,當然對于個人的代碼素養(yǎng)也是很有幫助的瓷炮,希望你能夠通過上文能夠加強你的代碼規(guī)范,寫出易讀易維護的代碼递宅。
代碼的規(guī)范屬于戰(zhàn)術上的進化崭别,下面我們再來看看如何讓你的Javascript在戰(zhàn)略上進化。
面向對象書寫Javascript
面向對象書寫Javascript想必你一定不會陌生恐锣,但我敢說茅主,大多數(shù)前端一般不會通過面向對象來書寫JS代碼。第一是Javascript本身的語言機制原因造成面向對象的書寫困難土榴,由于Javascript是原型式繼承又是一個類C的語言诀姚,他的面向對象的東西相對于C++/Java比較奇怪。第二是Javascript作為一種語法極其靈活的語言玷禽,直接導致了面向對象書寫JS又有多種寫法赫段,讓許多初學者分不清到底哪個才是正確的寫法呀打。基于上述和個人的經驗推薦如下倆種書寫方式:
第一類:
(function(){
function Circle(nRadius){
this.nR = nRadius;
}
Circle.prototype = {
PI : 3.14,
fnGetArea : function(){
return this.PI * this.nR * this.nR;
}
}
var c1 = new Circle(5);
alert(c1.fnGetArea()); //78.5
})();
上面這種可以說是很標準的面向對象JS書寫方式了我們又稱之為工廠模式糯笙,優(yōu)點就是簡單容易上手贬丛,新手常常喜歡這么寫。以上代碼略微做些改動给涕,會有如下這個變種:
(function(){
function Circle(nRadius, sMessage){
this.init.apply(this, arguments);
}
Circle.prototype = {
init : function(nRadius, sMessage){
this.nR = nRadius;
this.sMessage = sMessage;
},
PI : 3.14,
fnGetArea : function(){
return this.sMessage + ": " + this.PI * this.nR * this.nR;
}
}
var c = new Circle(5, "構造初始化 面積");
alert(c.fnGetArea()); //構造初始化 面積: 78.5
})();
上面這個變種豺憔,就比較有意思了,this.init.apply(this, arguments);這行代碼把初始化的任務交接給了init()方法够庙,這么做的好處就是可以把所有初始化的東西都放在一個地方進行恭应,增加可閱讀性,需要理解一定的Javascript運行機制原理耘眨。
第二類:
(function(){
function Circle(){
}
Circle.prototype = {
init : function(nRadius, sMessage){
this.nR = nRadius;
this.sMessage = sMessage;
},
PI : 3.14,
fnGetArea : function(){
return this.sMessage + ": " + this.PI * this.nR * this.nR;
}
}
var c = new Circle();
c.init(5, "手動構造初始化 面積");
alert(c.fnGetArea()); //手動構造初始化 面積: 78.5
})();
這類寫法是我現(xiàn)在比較喜歡的寫法昼榛,簡潔高效。從書寫角度來看省去了構造函數(shù)初始化屬性剔难,改用其init()中初始化胆屿。另一個好處在于不在new Circle()構造之初傳入參數(shù),個人認為當new構造對象的時候偶宫,最好不要摻雜參數(shù)莺掠,這樣做很“危險”,改為“手動型”初始化更易于代碼排查修改读宙。當然這種寫法還有一個原因就是他可以很好的轉換成一般前端接受的“封裝型”代碼,我們把上面的代碼也略微改動一下:
(function(){
var Circle = {
init : function(nRadius, sMessage){
this.nR = nRadius;
this.sMessage = sMessage;
},
PI : 3.14,
fnGetArea : function(){
return this.sMessage + ": " + this.PI * this.nR * this.nR;
}
}
Circle.init(5, "封裝型 面積");
alert(Circle.fnGetArea()); //封裝型 面積: 78.5
})();
是不是對上面這類代碼很熟悉楔绞,很多網站上的例子都是使用這類封裝型代碼書寫的结闸,優(yōu)點是代碼的封裝性良好,可以有效的重用酒朵,多用于頁面功能性效果實現(xiàn)桦锄,封裝一個Tab控件、封裝一個跑馬燈效果等等蔫耽。缺點就是不能很好的用作繼承结耀,這是和上面三種格式最大區(qū)別〕渍。可話又說回來一般JS代碼很少會用到繼承的地方图甜,除非是寫一個大型庫(類似YUI)會用到繼承外,一般寫一個功能模塊用到封裝型代碼就夠用了鳖眼,所以大多數(shù)前端喜歡使用這類封裝型的書寫風格黑毅。
上面介紹了2類4種面向對象的寫法,一般面向對象書寫格式基本都在上面了钦讳,熟悉面向對象書寫可以有效的增加你對JS的理解矿瘦。熟練使用上面4中寫法也能夠很好的在工作中給代碼維護修改帶來便利枕面。最后我們再來談一個技巧,讓你的Javascript代碼在技巧上進化缚去。
用對象字面量構造對象
一個對象字面量就是包含在一對花括號中的0個或多個“名/值”對潮秘。上文在面向對象書寫格式的時候我們就大量的使用了對象字面量的書寫格式。
對象字面量書寫Javascript可以很好的簡化代碼易结,又能極大的增加代碼可讀性枕荞,尤其作為參數(shù)使用可以有化腐朽為神奇的表現(xiàn)。我們看下面代碼:
(function(){
function Person(sName, nAge, nWeight, bSingle){
this.sName = sName;
this.nAge = nAge;
this.nWeight = nWeight;
this.bSingle = bSingle;
}
Person.prototype.showInfo = function(){
return this.sName + " " + this.nAge + " " + this.nWeight + " " + this.bSingle;
}
var p = new Person("海玉", 25, 75, true);
alert(p.showInfo()); //海玉 25 75 true
})();
上面是一個很標準的工廠模式衬衬,一般而言這類寫法屬于那種規(guī)規(guī)矩矩沒有大錯也沒有亮點的代碼买猖,而且參數(shù)不少,一個不小心還會傳入錯誤的參數(shù)滋尉,而應用對象字面量技巧可以很好的規(guī)避此類問題玉控,我們來看改動過后的代碼:
(function(){
function Person(){
}
Person.prototype = {
init : function(option){
if(typeof option == "undefined"){
option = {};
}
this.sName = option.sName || "海玉";
this.nAge = option.nAge || 25;
this.nWeight = option.nWeight || 75;
this.bSingle = (typeof option.bSingle != "undefined") ? option.bSingle : true;
},
showInfo : function(){
return this.sName + " " + this.nAge + " " + this.nWeight + " " + this.bSingle;
}
}
var p = new Person();
p.init({
nWeight : 80,
sName : "Hank"
})
alert(p.showInfo()); //Hank 25 80 true
})();
這里使用第三種面向對象寫法,有興趣的朋友可以自行嘗試改成封裝型寫法狮惜。上面的改寫看出哪里改動最大嗎高诺?對的,傳入參數(shù)改成了一個對象字面量碾篡,而且傳入參數(shù)可以是隨意設置虱而,位置顛倒也不會有任何問題。這里充分利用對象字面量優(yōu)點开泽,利用鍵值對代替原始的傳參方式大大提升了可讀性和容錯性牡拇。還有一個改進就是默認值的處理,如果沒有傳入任何參數(shù)穆律,此代碼也能很好的運行下去惠呼,不會有任何問題。
注1:這里形參命名為option峦耘,沒有遵守上面的變量命名規(guī)范是為了方便書寫與閱讀剔蹋,具體情況具體分析。
注2:由于||運算符對于布爾值默認賦值會出現(xiàn)賦值問題辅髓,所以要先進行判斷是否為undefined泣崩,再利用三元運算符可以很好的完成布爾值的默認值賦值。
總的來說上面闡述的代碼進化只能算的上是“修身”層面洛口,想要真正的讓代碼“修心”還是得多寫矫付,多看,多練第焰。只有這樣你的代碼才會更精練技即,更有擴展性,更好的維護性。
林林總總寫了這些個總結而叼,一來是對自己學習的記錄身笤,二來也是想同大家探討JS還有哪些地方有潛力可挖,腦子里還有許多零零碎碎的片段葵陵,待日后再次整理驗證再與大家一起分享吧液荸。