代碼風(fēng)格
命名
1. 為方法、變量取一個好名字, 使代碼易于理解
2. 文件中的私有屬性和方法名應(yīng)該以“__“開頭
3. 常量定義全部大寫, 并用下劃線分隔單詞
4. 方法的命名, 用動詞和動賓結(jié)構(gòu), 并采用首字母小寫的駝峰命名法。
說明:
get + 非布爾屬性名()
is + 布爾屬性名()
set + 屬性名()
has + 名詞/形容詞()
動詞()
動詞 + 賓語()
5. 為保證可讀性, 方法名不宜過長
6. 函數(shù)名、屬性名遵循駝峰命名風(fēng)格
7. 為全局屬性、函數(shù)使用命名空間
8. 不要采用保留字作為鍵值或變量名, 如果確實需要, 請用保留字的同義詞
9. jQuery類型的變量以$開頭
注釋
- 盡量讓代碼來解釋自己
- 注釋應(yīng)解釋代碼的意圖, 而不是描述代碼怎么實現(xiàn)的
- 保證注釋與代碼一致, 避免產(chǎn)生誤導(dǎo)
- 注釋應(yīng)與其描述代碼位置相鄰, 放在所注釋代碼的上方或右方, 并與代碼采用同樣的縮進
- 注釋和上面的代碼塊要有空行, 注釋的//和注釋內(nèi)容要有一個空格
- 不要用注釋保留廢棄的代碼
- 不要用注釋記錄修改日志
- 一般單行用
//塊用/* */文檔注釋用/** */
排版
1. 團隊?wèi)?yīng)使用一致的排版風(fēng)格
2. 將排版風(fēng)格固化到IDE的代碼格式化配置文件中, 并讓整個團隊使用
3. 在不同概念之間 , 增加空行
4. 將邏輯緊密相關(guān)的代碼放在一起
5. 控制一行的寬度, 不要超過120個字符
6. 在不同的概念間(關(guān)鍵字, 變量, 操作符)增加空格, 以便清楚區(qū)分概念。
7. 統(tǒng)一采用4空格縮進
8. 數(shù)組和對象初始化, 如果初始值不是很長, 就保持寫在單行上。
9. 給if, for, do, while, switch等語句的執(zhí)行體加大括號{}
10. 控制文件的長度, 最好不要超過500行
11. 如果參數(shù)中有匿名函數(shù), 函數(shù)體從調(diào)用該函數(shù)的左邊開始縮進4個空格, 而不是從function這個關(guān)鍵字開始, 這讓匿名函數(shù)更加易讀
12. 二元和三元操作符始終跟隨著前行, 如果一行實在放不下, 按上述的縮進風(fēng)格進行換行
13. 字符串優(yōu)先使用單引號
14. 使用方法鏈時進行縮進, 同時使用前面加點, 強調(diào)這是方法調(diào)用而不是語句, 如:
$(".item")
.find("tr")
.end()
.find(".open");
15. 花括號和語句在同一行。
16. 花括號前加一個空格
17. 在控制語句(if, while等)的括號前放一個空格, 在函數(shù)調(diào)用及聲明中, 不在函數(shù)的參數(shù)列表前加空格。
方法
1. 方法設(shè)計的第一原則是要短小
2. 方法設(shè)計要遵循單一職責(zé)原則(SRP), 一個方法僅完成一個功能
3. 方法設(shè)計應(yīng)遵循單一抽象層次原則(SLAP)
SLAP原則, 是指一個方法中所有的操作處于相同的操作層, 否則, 跳躍的代碼的抽象層次破壞了代碼的流暢性。
4. 不要把方法的入?yún)?dāng)做工作變量/臨時變量, 除非特別需要
說明:
- 每個變量/參數(shù)都有自己獨特的功能, 讓一個變量承擔(dān)多個職責(zé), 變量名無法清晰表達其功能, 會使程序無法理解。
- 如果參數(shù)是傳引用方式的, 則方法內(nèi)對參數(shù)的修改, 會傳遞到方法外, 造成意外的錯誤, 如傳引用時, 不想方法內(nèi)修改入?yún)⒌模?建議在參數(shù)前加final關(guān)鍵字。
5. 方法的參數(shù)個數(shù)不宜過多
如果參數(shù)超過了7個, 則維護的難度很大, 建議減少參數(shù)個數(shù)。 如果多個參數(shù)同時多次出現(xiàn)在多個方法中, 說明這些參數(shù)緊密相關(guān), 可以將它們封裝到一個對象中。
語言特性
1. 定義類時, 盡量在原型下定義方法, 在構(gòu)造函數(shù)內(nèi)定義屬性, 從而最大程度發(fā)揮JavaScript引擎優(yōu)化機制
說明: 原型可以降低內(nèi)在占用, 提高運行效率。
2. 向數(shù)組添加元素時, 使用Array.push替代直接賦值
3. 有替代方案時, 禁用使用eval方法
說明:
- eval接受一個參數(shù)content, 如果content不是字符串, 則直接返回content, 否則執(zhí)行content語句, 如果content語句執(zhí)行結(jié)果是一個值, 則返回此值, 否則,返回undefined, 這讓程序比較混亂, 導(dǎo)致可讀性差。
- 當(dāng)eval()里面包含用戶輸入的話, 存在安全風(fēng)險, 可以用其它更佳、更清晰、更安全的方式來寫代碼。
4. 禁止使用with(){}
使用with讓你的代碼在語義上變得不清晰, 因為with的對象可能與局部變量產(chǎn)生沖突, 從而改變你程序原本的用義。
5. 僅在對象構(gòu)造器、方法和閉包中使用this
- 在JavaScript里面, this指針代表的是執(zhí)行當(dāng)前代碼對象的所有者, this語義很特別:
- 全局對象(大多數(shù)情況下)
- 調(diào)用者的作用域(使用eval時)
- DOM樹中的節(jié)點(添加事件處理函數(shù)時)
- 新創(chuàng)建的對象(在構(gòu)造器時)
- 其他對象(如果函數(shù)被call()或apply())
- 使用this時很容易出錯, 所有只有在下面兩種情況下使用:
- 在構(gòu)造器中
- 對象的方法(包括創(chuàng)建的閉包)中
6. 塊內(nèi)函數(shù)必須使用函數(shù)表達式聲明, 塊內(nèi)變量不能與函數(shù)內(nèi)的其他變量同名
7. 使用JSON.parse方法來分析JSON字符串
8. 每句代碼后必須加分號(;)
9. 使用JavaScript字面量而不是封裝基本類
10. 禁止修改內(nèi)置對象的原型
11. JavaScript與HTML分離
12. 聲明變量必須加var關(guān)鍵字
13. 在函數(shù)內(nèi)部使用”use strict"
說明:
- 消除JavaScript語法的一些不合理、不嚴(yán)謹(jǐn)之處, 減少一些怪異行為
- 消除代碼運行的一些不安全之處, 保證代碼運行的安全
- 提高編譯器效率, 提高運行速度
- 為未來新版本的JavaScript做好鋪墊
在開啟“use strict"后, 以下情況在運行腳本前會拋出SyntaError異常
- 八進制語法:
var n = 023或var s = \047 - with語句
- 使用delete刪除一個變量名或函數(shù)(不是屬性名)
- 使用eval或arguments作為變量名或函數(shù)名
- 使用未來保留字
- 在語句塊使用函數(shù)聲明, 如
if(a>b){function f(){}} - 對象字面量中使用相同的屬性名
- 函數(shù)形參中使用多個相同的參數(shù)名
14. 訪問外部對象或外部對象屬性時, 必須先判斷是否為空
15. 判斷相等時, 使用===和!==
16. 使用for/in循環(huán)必須結(jié)合實際具體應(yīng)用場景, 正確使用hasOwnProperty方法
說明:
- for/in主要用于遍歷對象的屬性, 但不包括對象的內(nèi)置成員(如toString, valueOf)
- 如果重寫了Object的內(nèi)置屬性, 使用for/in遍歷在不同瀏覽器上的結(jié)果是不同的
- 如果往原生對象上增加方法或?qū)傩裕?會被遍歷出來, 如果不是業(yè)務(wù)需要遍歷property內(nèi)的屬性, 都要使用hasOwnProperty方法來提高代碼的健壯性
- 遍歷數(shù)組禁止使用for/in做遍歷, 請用普通的for循環(huán)來做遍歷。
17. 盡量避免給數(shù)組添加屬性
18. 推薦使用簡寫的條件表達式
19. 不要寫復(fù)雜的表達式
20. 采用括號明確計算的優(yōu)先級
21. 在switch語句的每一個case和default中都放置一條break語句。
22. var聲明會被提升至該作用域頂部, 所以聲明變量應(yīng)該寫在作用域頂部(因為即使var聲明不在頂部, 其實也會默認(rèn)提升到作用域頂部, 所以顯式地寫在頂部可讀性更強).
性能編程規(guī)范
1. 緩存jQuery查詢結(jié)果
使用JavaScript訪問DOM元素是比較慢的, 所以使用選擇器的次數(shù)應(yīng)該越少越好, 并且盡可能緩存選中的結(jié)果, 便于后續(xù)反復(fù)使用
2. 避免使用所有元素選擇器$("*")
3. 優(yōu)先使用ID選擇器, 盡量給選擇器指定上下文context
jQuery選擇器性能最佳到最差如下:
- id選擇器
- 元素選擇器
- 類選擇器
- 屬性選擇器
- 偽類選擇器
4. 循環(huán)中減少DOM操作
5. 利用事件代理(冒泡)機制
每個JavaScript事件(如click)都會冒泡到父級節(jié)點, 當(dāng)需要給多個元素調(diào)用同一個函數(shù)時, 這點很有用.
6. 盡量不要使用同步的ajax
同步的ajax請求會阻塞界面的渲染, 讓界面產(chǎn)生卡頓情況
內(nèi)存編程規(guī)范
1. 在滿足業(yè)務(wù)特性需求的情況下, 減少DOM對象的動態(tài)創(chuàng)建和刪除.
2. 禁止在循環(huán)、事件操作回調(diào)中使用文本+變量拼接的方式使用jQuery創(chuàng)建DOM。
說明:
jQuery在內(nèi)部實現(xiàn)中為了提高頻繁的DOM創(chuàng)建的性能, 會使用DocumentFragment緩存用戶創(chuàng)建的DOM, 在重復(fù)創(chuàng)建的過程中使用緩存的DOM對象clone創(chuàng)建DOM, 從而提高DOM創(chuàng)建的效率。 但是, 這一優(yōu)化, 僅適用于用戶頻繁創(chuàng)建的DOM內(nèi)容沒有變化的情況, 對于內(nèi)容不斷變化的話, 在頁面沒有卸載的情況下長時間運行
例如(不好)
$("#btn").on("click", function(e){
var ele = $("#hostelement");
var content = getValue();
var $span = $("<span>" + content + "</span>")
ele.append($span);
});
該方式下, jQuery不會生成DocumentFragment對象, 也不會緩存DOM對象在其內(nèi)部的變量中, 因此重復(fù)、頻繁使用時不會造成DOM泄露產(chǎn)生的問題內(nèi)存上漲。
3. 盡量不要使用iframe
說明:
iframe適用于第三方集成, 文件異步上傳等業(yè)務(wù), 非此類業(yè)務(wù)時, 建議使用HTML方式構(gòu)建, 而不要使用iframe, iframe在加載性能和反復(fù)刪除情況下的內(nèi)存回收都不太理想, 尤其是低版本的瀏覽器。
事件監(jiān)聽
1. 正確使用DOM Event Level 2/3 標(biāo)準(zhǔn)進行事件的綁定和注銷。
2. 頁面卸載、動態(tài)刪除的DOM對象時要注銷綁定的事件監(jiān)聽。
說明:
通常事件監(jiān)聽都是與DOM對象掛鉤的, 當(dāng)事件監(jiān)聽沒有被注銷時, 可能會造成JavaScript對象與DOM對象之間存在引用關(guān)系, 尤其在大量使用閉包的情況下, 容易造成JavaScript對象和DOM的循環(huán)引用。 在IE、firefox上會造成內(nèi)存泄露, 原因是由于IE和firefox都使用引用計數(shù)方式的垃圾回收算法。
var $btn = $(".btn");
$btn.off();
$btn.remove();
3. 不要在HTML標(biāo)簽上嵌入JavaScript事件回調(diào)代碼
說明:
直接將JavaScript字符串作為DOM的事件處理邏輯, 容易引發(fā)IE8版本下無法釋放內(nèi)存的問題。
其它
1. 頁面局部刷新調(diào)整時, 要注銷相應(yīng)的定時器和延時器。
說明:
定時器和延時器容易造成JavaScript對DOM的引用, 在JavaScript對象本身沒有被釋放的情況下, 容易引起DOM對象的泄露。
在局部頁面刷新時, 必須清理相應(yīng)的定時器, 否則會造成多個定時器同時執(zhí)行的業(yè)務(wù)問題和每個定時器對應(yīng)閉包所引用的內(nèi)存無法釋放的問題。
2. 不要在JavaScript代碼中使用console.log輸出。
說明:
console.log輸出會導(dǎo)致瀏覽器內(nèi)存上漲。 在IE下, 只要打開F12, console就會被激活, 后面即使關(guān)閉F12工具也無法關(guān)閉掉console, 內(nèi)存依然占用。
3. 使用完數(shù)組要將數(shù)組的長度置空
說明:
JavaScript是通過引用傳參, 需要在接口中或模塊中明確數(shù)組對象的生命周期責(zé)任, 否則可能會造成一處已經(jīng)置null, 而別處仍然持有引用, 導(dǎo)致內(nèi)存沒有釋放。