咱們通常用循環來遍歷數組,而循環一直是 JavaScript 性能問題的常見來源,有時循環用得很差會嚴重下降代碼的運行速度。例如,遍歷數組時,咱們會很天然地寫出下面這種代碼:數組
// 未優化的代碼1
var array = [0,1,2,3,4,5,6,7,8,9];性能// for-in 循環
for (var val in array) {
fn(val); -> should be fn(array[val])
}優化
還有這一種常見寫法:spa
// 未優化的代碼2
var array = [0,1,2,3,4,5,6,7,8,9];對象// for 循環
for (var i=0; i < array.length; i++) {
fn(array[i]);
}ip
這兩個方法看上去彷佛不錯,並且語義上也很容易理解。可是這兩個方法都有性能問題:get
「未優化的代碼1」中,for-in 須要分析出 array 的每一個屬性,這個操做的性能開銷很大,用在 key 已知的數組上是很是不划算的。因此儘可能不要用 for-in,除非你不清楚要處理哪些屬性,例如 JSON 對象這樣的狀況。class
「未優化的代碼2」中,循環每執行一次,都要檢查一次 array.length 的值,讀屬性要比讀局部變量慢,尤爲是當 array 裏存放的都是 DOM 元素(像 array = document.getElementByClassName("class");),由於每次讀 array.length 都要掃描一遍頁面上 class="class" 的元素,速度更是慢得抓狂。變量
假如你的任務是從頁面上 100 個複選框中,找出選中的複選框的 value,並把它們放入一個數組的話,在 IE 上可能得花上半秒才能完成。結果就是,用戶在列表裏選擇了本身要的項目,點擊提交後起碼要過半秒纔會有反應,直觀感受就是很卡。循環
咱們毫不能接受這樣的結果,因此咱們須要加快循環終止條件的計算速度。先把數組的長度先查出來,存進一個局部變量,那麼循環的速度將會大大提升:
// 快速的代碼
var array = [0,1,2,3,4,5,6,7,8,9];// for 循環
var length = array.length;
for (var i=0; i < length; i++) {
fn(array[i]);
}
如今只須要讀取一次 array.length 的值,遍歷數組的過程大大加快了。
不過咱們還可讓它更快。若是循環終止條件不須要進行比較運算,那麼循環的速度還能夠更快:
// 最快的代碼
var array = [0,1,2,3,4,5,6,7,8,9];// for 循環
for (var i = array.length; i--;) {
fn(array[i]);
}
把數組下標改爲向 0 遞減,循環終止條件只須要判斷 i 是否爲 0 就好了。由於循環增量和循環終止條件結合在一塊兒,因此能夠寫成更簡單的 while 循環:
// 最快且優雅的代碼
var array = [0,1,2,3,4,5,6,7,8,9];// while 循環
var i = array.length;
while (i--) { fn(array[i]); }