4.1 JScript性能優化的基本原則
1. 盡可能少地減少執行次數。畢竟對解釋語言來說,每一個執行步驟,都需要和解釋引擎做一次交互。
2. 盡可能使用語言內置的功能,比如串鏈接。
3. 盡可能使用系統提供的API來進行優化。因為這些API是編譯好的二進制代碼,執行效率很高。
4. 書寫最正確的代碼。容錯功能是要付出性能代價的。
4.2 JScript語言本身的優化
4.2.1 變量
1. 盡量使用局部變量。
因為全局變量其實是全局對象的成員,而局部變量在棧上定義,優先查找,性能相對于全局變量要高。
2. 盡量在一個語句中做定義變量和賦值。
3. 省略不必要的變量定義。
如果變量的定義可以被一個常量替代,就直接使用常量。
4. 使用Object語法對對象賦值。
Object的賦值語法在操作復雜對象時效率更高。
例如,可以將下面的代碼:






替換成:









4.2.2 對象緩存
1. 緩存對象查找的中間結果。
因為JavaScript的解釋性,所以a.b.c.d.e,需要進行至少4次查詢操作,先檢查a再檢查a中的b,再檢查b中的c,如此往下。所以如果這樣的表達式重復出現,只要可能,應該盡量少出現這樣的表達式,可以利用局部變量,把它放入一個臨時的地方進行查詢。
2. 緩存創建時間較長的對象。
自定義高級對象和Date、RegExp對象在構造時都會消耗大量時間。如果可以復用,應采用緩存的方式。
4.2.3 字符串操作
1. 使用"+=" 追加字符串,使用"+"來連接字符串。
如果是追加字符串,最好使用s+=anotherStr操作,而不是要使用s=s+anotherStr。
如果要連接多個字符串,應該使用"+",如:
s+=a;
s+=b;
s+=c;
應該寫成
s+=a + b + c;
2. 連接大量的字符串,應使用Array的join方法。
如果是收集字符串,最好使用JavaScript數組緩存,最后使用join方法連接起來,如下:









4.2.4 類型轉換
1. 使用Math.floor()或者Math.round()將浮點數轉換成整型。
浮點數轉換成整型,這個更容易出錯,很多人喜歡使用parseInt(),其實parseInt()是用于將字符串轉換成數字,而不是浮點數和整型之間的轉換,我們應該使用Math.floor()或者Math.round()。
對象查找中的問題不一樣,Math是內部對象,所以Math.floor()其實并沒有多少查詢方法和調用的時間,速度是最快的。
2. 自定義的對象,推薦定義和使用toString()方法來進行類型轉換。
對于自定義的對象,如果定義了toString()方法來進行類型轉換的話,推薦顯式調用toString()。因為內部的操作在嘗試所有可能性之后,會嘗試對象的toString()方法嘗試能否轉化為String,所以直接調用這個方法效率會更高。
4.2.5 循環的優化
1. 盡可能少使用for(in)循環。
在JavaScript中,我們可以使用for(;;),while(),for(in)三種循環,事實上,這三種循環中for(in)的效率極差,因為他需要查詢散列鍵,只要可以就應該盡量少用。
2. 預先計算collection的length。
如:將
for (var i = 0; i < collection.length; i++)
替換成:
for (var i = 0, len = collection.length; i < len; i++)
效果會更好,尤其是在大循環中。
3. 盡量減少循環內的操作。
循環內的每個操作,都會被放大為循環次數的倍數。所以,大循環內微小的改進,在性能的整體提升上都是可觀的。
4. 使用循環替代遞歸。
相比循環,遞歸的效率更差一些。遞歸的優點是在形式上更自然一些。所以,在不影響代碼的維護性的前提下,用循環替代遞歸。
4.2.6 其它方面
1. 盡量使用語言內置的語法。
"var arr = […];"和"var arr = new Array(…);"是等效的,但是前者的效能優于后者。同樣,"var foo = {};"的方式也比"var foo = new Object();"快;"var reg = /../;"要比"var reg=new RegExp()"快。
2. 盡量不要使用eval。
使用eval,相當于在運行時再次調用解釋引擎,對傳入的內容解釋運行,需要消耗大量時間。
3. 使用prototype代替closure。
使用closure在性能和內存消耗上都是不利的。如果closure使用量過大,這就會成為一個問題。所以,盡量將:
this.methodFoo = function()
替換成:
MyClass.protoype.methodFoo = function()
和closure存在于對象實例之中不同,prototype存在于類中,被該類的所有的對象實例共享。
4. 避免使用with語句。
With語句臨時擴展對象查找的范圍,節省了文字的錄入時間,但付出了更多的執行時間。因為每個給出的名稱都要在全局范圍查找。所以,可以將下面的代碼:







變更為:



4.3 DOM相關
4.3.1 創建DOM節點
相比較通過document.write來給頁面生成內容,找一個容器元素(比如指定一個div或者span)并設置他們的innerHTML效率更高。
而設置innerHTML的方式比通過createElement方法創建節點的效率更高。事實上,設置元素的innerHTML是創建節點效率最高的一種方式。
如果必須使用createElement方法,而如果文檔中存在現成的樣板節點,應該是用cloneNode()方法。因為使用createElement()方法之后,你需要設置多次元素的屬性,使用cloneNode()則可以減少屬性的設置次數。同樣,如果需要創建很多元素,應該先準備一個樣板節點。
4.3.2 離線操作大型的DOM樹
在添加一個復雜的DOM樹時,可以先構造,構造結束后再將其添加到DOM數的適當節點。這能夠節省界面刷新的時間。
同樣,在準備編輯一個復雜的樹時,可以先將樹從DOM樹上刪除,等編輯結束后再添加回來。
4.3.3 對象查詢
使用[""]查詢要比.item()更快。調用.item()增加了一次查詢和函數的調用。
4.3.4 定時器
如果針對的是不斷運行的代碼,不應該使用setTimeout,而應該用setInterval。setTimeout每次要重新設置一個定時器。
4.4 其他
1. 盡量減小文件尺寸。
將JScript文件中無關的空行、空格、注釋去掉,有助于減小JS文件的尺寸,提高下載的時間。(可以通過工具來支持代碼發布)
2. 盡量不要在同一個Page內同時引用JScript和VBScript引擎
3. 將Page內的JScript移入到單獨的JS文件中。
4. 將Page內的JScript放置在Page的最下面,有助于提高頁面的響應速度。
5. 利用cache,減少JScript文件的下載次數
6. 在HTML內書寫JScript文件的URL時,注意統一大小寫。這樣可以利用前面URL緩存的文件。
7. 推薦使用JScript Lint檢查Javascript代碼。畢竟,對JScript引擎來說,最容易理解的JScript代碼,執行的效率也就最高。