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






替換成:









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









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







變更為:



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