一。可維護性優化
###1. 添加註釋
註釋能夠增強代碼的可讀性以及可維護性,當然,理想情況是滿滿的註釋,但這不太現實。所以我們只需要在一些關鍵的地方添上註釋:
-
函數和方法:尤其是返回值,因為直接看不出來
-
大段代碼(功能模組):說明模組功能
-
複雜算法:寫出關鍵點,方便理解
-
Hack:說明為了修復什麼問題,當前方案是否完善,能否改進
###2.「暗示」變量類型
通過初始值來暗示,例如:
var found = false;
var count = 1;
var name = '';
var student = null;
###3. 解耦(分層)
-
結構層:HTML
-
行為層:JS
-
表現層:CSS
盡量不要「越權」,如果實在是想越權,也應該用文檔或者註釋說明。盡量不要出現緊耦合,例如:
-
JS-HTML:
elem.innerHTML = '<div class="block"><h2>title</h2><p>content</p></div>'; //最好用下面的方式代替(顯示頁面中的隱藏元素) //elem.style.display = 'block'; -
JS-CSS:
elem.style.color = '#e0e0e0'; //最好用下面的方式代替(設置類,不要直接設置樣式) //elem.className = 'my_class'; -
JS-JS:
//邏輯耦合 elem.onclick = function(e){ if(txt.value !== null && txt.value !== '' &&...){ //DOM 操作 } } //最好用下面的方式代替(分離邏輯功能塊) function isValid(){ return txt.value !== null && txt.value !== '' &&...; } function display(){ //DOM 操作 } elem.onclick = function(e){ if(isValid()){ display(); } }
避免邏輯耦合的幾條原則:
-
不要傳遞 event 對象,只傳需要的數據
-
觸發事件不應該是執行動作的唯一方式
-
事件處理器應該只處理事件相關數據(獲取事件源,坐標值等等),然後把處理轉交給應用邏輯
###4. 編碼原則
-
尊重對象所有權,不要隨便修改別人的對象,具體要求:
-
不要給實例/原型添加屬性或方法
-
不要重寫已存在的方法
-
可選方案:
- 組合:創建實現了所需功能的新對象,引用需要的對象
- 繼承:創建自定義類型,繼承需要修改的類型,然後添加額外功能
-
用命名空間避免全域變量,例如:
var mySystem = {}; mySystem.mod1 = {...}; -
用常量提高可維護性,例如:
var Consts = {}; Consts.IMG_PATH = '../imgs/';
注意:常量包括常用的 CSS 類名和其它任何可能影響維護的值
二。性能優化
###1. 避免長作用域鏈查找
把需要多次引用的全域變量另存為局部變量
###2. 盡量不要用 with 語句
with 語句會延長作用域,存在長作用域查找的開銷,可以用另存局部變量來代替(沒有 with 方便,但多少能好一點)
###3. 避免不必要的屬性查找
-
盡量把重複使用的值另存為局部變量,例如:
//不要用下面的代碼(6 次屬性查找) var qs = window.location.href.substring(window.location.href.indexOf('?')); //應該用下面的代碼(4 次,而且更具可讀性) var url = window.location.href; var qs = url.substring(url.indexOf('?')); -
優化循環
-
減值迭代更快(i--)
-
簡化終止條件,每次循環都會檢查終止條件,簡化條件能提高效率
-
簡化循環體,盡量減少循環體裡面的計算量
-
使用後測試循環(do...while),可以避免第一次循環前的判斷
-
-
展開循環
如果循環次數確定,最好不要用循環,因為循環存在創建循環和處理終止條件的額外開銷,例如:
for(i = 0;i < 2;i++){
process(arr[i]);
}
//下面的比上面的快
process(arr[0]);
process(arr[1]);
process(arr[2]);
如果循環次數不能確定,可以用 Duff 技術(Tom Duff 發明的)展開一部分循環,提高效率,例如:
//credit: Jeff Greenberg for JS implementation of Duff's Device
//假設 values.length > 0
var iterations = Math.ceil(values.length / 8);
var startAt = values.length % 8;
var i = 0;
do {
switch(startAt){
case 0: process(values[i++]);
case 7: process(values[i++]);
case 6: process(values[i++]);
case 5: process(values[i++]);
case 4: process(values[i++]);
case 3: process(values[i++]);
case 2: process(values[i++]);
case 1: process(values[i++]);
}
startAt = 0;
} while (--iterations > 0);
//以上代碼來自:http://www.cnblogs.com/kylindai/archive/2013/12/04/3458476.html
或者另一個更快的 Duff 方法:
//credit: Speed Up Your Site (New Riders, 2003)
var iterations = Math.floor(values.length / 8);
var leftover = values.length % 8;
var i = 0;
if (leftover > 0){
do {
process(values[i++]);
} while (--leftover > 0);
}
do {
process(values[i++]);
process(values[i++]);
process(values[i++]);
process(values[i++]);
process(values[i++]);
process(values[i++]);
process(values[i++]);
process(values[i++]);
} while (--iterations > 0);
//以上代碼來自:http://www.cnblogs.com/kylindai/archive/2013/12/04/3458476.html
4. 避免雙重解釋
雙重解釋是指:用 js 解析 js。具體是用 eval() 函數或者 new Function(strCode) 或者 setTimeout(strCode)
雙重解釋的缺點:需要再啟動一個解析器來解析,存在很大的開銷,比直接解析慢很多
- 原生方法更快
原生方法是用用 C/C++ 編譯好的模組,所以要快得多
- switch 比 if-else 快
原因不好說,可以參考 CSDN
- 位運算並沒有更快
在其它語言中把數學運算簡化為位運算能夠提升計算速度,但js 中沒這一說,因為 js 內部只有一種數值類型(double),所以做位運算需要折騰:double - int - 做位運算 - double,性能可想而知
-
減少語句數量
-
用 1 個 var 聲明多個變量
-
插入迭代值,arr[i++] 一條語句搞定,不用把 i++ 獨立成一個語句
-
用數組/對象字面量,代碼行數明顯變少了
-
-
DOM 優化
-
減少現場更新,可以用 DocumentFragment 優化
-
用 innerHTML 創建 DOM 節點比創建一堆節點再組裝要快,但存在 JS-HTML 耦合問題,慎重考慮
-
用事件委託
-
注意實時更新的集合(NodeList、NamedNodeMap、HTMLCollection)
除了把引用另存為局部變量外,還要注意訪問其屬性也是需要重新查詢的,比如:var imgs = document.images; 訪問 imgs.length 也需要再查一次
-
三。發布優化
-
用驗證工具(如 JSLint)檢查代碼,發現語法錯誤之外的潛在問題
-
去掉註釋(出於安全性考慮)
-
合併 js 文件,盡量減少外部文件數量
-
壓縮代碼(如 YUI 壓縮器),減少代碼本身大小,也可以同時混淆代碼,提高安全性,但混淆代碼本身存在風險,可能引發錯誤
-
開啟服務器壓縮功能,例如 gzip 模組
暫無評論,快來發表你的看法吧