在大部分程式語言中, 迴圈語句消耗了大部分時間
而循環語句又是十分重要的程式模式
在我們JavaScript中, 有四種循環類型
for循環
while迴圈
do-while迴圈
for-in迴圈
其中前三種循環在其他語言也很常見
for-in循環對於在學校學過C/C++的同學來說也許很新鮮
它每次迭代的同時會搜尋實例和原型屬性, 所以它每次迭代便會產生更多的開銷
for-in循環最終只有其他三種類型速度的1/7
所以, 除非我們明確需要迭代一個屬性數量未知的物件, 否則我們應盡量避免使用for-in
更不要用for-in循環去遍歷數組
我們可以這樣去迭代一個明確的物件
var props = ['prop1', 'prop2'], i = 0;while(i < props.length){ fn(obj[props[i++]]); }
這段程式碼根據物件中的屬性, 建立一個物件屬性的陣列, 然後透過while循環來遍歷屬性列表並處理對應屬性值
這樣就可以不用查找物件的每一個屬性, 減少了循環的開銷
上面做法的前提是物件內部的屬性是已知的
如果我們不知道物件內部的實作
還要處理物件本身的屬性,只能這樣做了
for(var prop in obj){ if(obj.hasOwnProperty(prop)){ //... } }
代價是每次迭代都要判斷這個屬性是不是物件自己的屬性而不是繼承來的
#除了for-in以外, 其他的循環性能都差不多, 所以使用的時候應該去考慮需求從而選擇循環類型
相信剛學習程式設計的小夥伴都是介樣寫循環的
for(var i = 0; i < arr.length; i++){ fn(arr[i]); }
這個循環語句每進行一次迭代, 都要去查找arr中的length屬性,這樣很耗時
所以我們可以進行優化,
for(var i = 0, len = arr.length; i < len; i++){ fn(arr[i]); }
把數組長度值緩存到一個局部變量, 這樣問題就解決了
while, do-while也是同理
根據數組長度, 很多瀏覽器中能節省大概25%的運行時間
我們還可以透過顛倒數組順序來略微提高性能
for(var i = items.length; i--;){ process(items[i]); }
var j = items.length;while(j--){ process(items[j]); }
var k = items.length - 1;do { process(items[k]); }while(k--);
這樣做每次迭代控制條件從兩次判斷(迭代數是否小於總數, 是否為true)
減少為一次判斷(是否為true), 進一步提高了循環速度
我們大家可能都用過一些數組方法比如arr.forEach()或者一些框架的迭代方法比如jQuery的$().each()去遍歷數組,
這些方法對數組的每一個元素執行一個函數
儘管它們很方便, 但它們要比普通的循環要慢很多(調用了外部的方法)
在所有情況下, 基於循環的迭代比基於函數的迭代快大約8倍
所以我們在能使用普通循環(for,while,do-while)解決問題的時候盡量用這些普通循環
#