各類循環遍歷對比

簡介

經常使用的循環遍歷語句有for、while、do-while以及for-in,forEach,map。javascript

循環語句

while

前測試循環語句,在循環體內代碼被執行前,就會對出口條件求值css

do-while

後測試循環語句,經常使用於循環體中的代碼至少要被執行一次html

for

是一種前測試循環語句,但它具備在執行循環以前初始化變量和定義循環後要執行的代碼的能力java

注意點:
1. 在變量的初始化表達式中,也能夠不使用 var關鍵字。
2. 只是把與循環有關的代碼集中到一個位置,while 循環作不到的,for循環也作不到
3. 在循環內部定義的變量在外部也能夠訪問到。如:nginx

var count = 10;

//初始化表達式中,能夠不使用 var關鍵字
for(i = 0 ; i < count ; i++){
    alert(i);
}

alert(i);   // 10

for-in

for-in通常是用在對象屬性名的遍歷上的,因爲每次迭代操做會同時搜索實例自己的屬性以及原型鏈上的屬性,因此效率確定低下;這個循環不少人愛用,但實際上,經分析測試,在衆多的循環遍歷方式中,它的效率是最低的git

for(var propName in window){
    document.write(propName);
}

注意點:
1. 在變量的初始化表達式中,也能夠不使用 var關鍵字。
2. 對象的屬性沒有順序,因此經過循環輸出的屬性名的順序是不可預測的。每一個屬性都會被返回一次,但返回的次序因瀏覽器而異
3. 低版本的瀏覽器可能會有兼容性的問題。如safari3之前的版本es6

forEach

數組自帶的foreach循環,使用頻率較高,是基於函數的迭代,因此實際上性能比普通for循環弱。github

myArray.forEach(function (value) {
  console.log(value);
});

注意點:
1. 不能中斷循環(使用break語句或使用return語句。
2. 須要特別注意的是全部版本的ie都不支持,若是須要能夠用JQuery等庫
3. 對每一個數組項調用外部方法所帶來的開銷是速度慢的主要緣由web

變種:
因爲foreach是Array型自帶的,對於一些非這種類型的,沒法直接使用(如NodeList),因此纔有了這個變種,使用這個變種可讓相似的數組擁有foreach功能。canvas

Array.prototype.forEach.call(arr,function(el){  
   
});

注意點:
一、實際性能要比普通foreach弱

map

這種方式也是用的比較普遍的,雖然用起來比較優雅,但實際效率還比不上foreach

arr.map(function(n){  
   
});

for-of(須要es6支持)

這種方式是es6裏面用到的,性能要好於forin,但仍然比不上普通for循環

for(let value of arr) {  
   
});

性能對比

性能優化

1. 優化變量聲明

JS不一樣與其餘面向對象的語言,他沒有塊及做用域,有的僅僅是函數做用域,因此當使用了一個變量,而後不久在函數中又從新聲明的話,就可能產生邏輯錯誤。對於JavaScript,只要你的變量是在同一個做用域中(同一函數),它都被當作是聲明的,即便是它在var聲明前使用的時候。合理的寫法即把變量聲明在函數的開始,而不是在循環內部纔開始定義變量。

//優化JS的變量定義,變量定義在開始位置,避免產生塊級做用域的誤區
    var i;
    for(i=0; i<values.length; i++){
        ...
    }

2. 優化循環中動態集合讀取
NodeList 、NameNodeMap 和 HTMLCollection,這三個集合每當文檔結構發生變化時,它們都會獲得更新(並且仍是動態的更新)。下面代碼中的divs 所引用的就是NodeList 對象

//致使NodeList無限循環的循環書寫方式
    var divs = document.getElementsByTagName("div");
    for(var i=0; i<divs.length; i++){
        var div =document.createElement("div");
        document.body.appendChild(div);
        alert("Infinite loop");
    }

上述代碼每次循環都要對divs.length 求值,循環代碼會致使一個嚴重的問題,每次循環都要對divs.length 求值。

如下是優化後的代碼:

//避免NodeList無限循環的循環書寫方式
var divs = document.getElementsByTagName("div");
//先將length用變量儲存起來
 for(var i=0, len = divs.length ; i<len; i++){
        var div =document.createElement("div");
        document.body.appendChild(div);
        alert("Infinite loop will not happen");
    }

3. 用i+=1 代替i++
從《Javascript語言精粹》裏面看來的,大體意思是說用了i++ 會有潛在的安全問題,i+=1 比起i++ 更加「原生」能夠提高性能,可是我的認爲可讀性下降,根據須要各自取捨吧。

4. 減值迭代優化循環
從最大值開始,在循環中不斷減值的迭代器更加高效(只高效了一點點)。若是值的處理順序可有可無,那麼循環能夠改成i 減值,可是下降可讀性,

//減值迭代優化循環
    for(var i=values.length-1; i>=0; i--){
    ...
    }

循環優化大串聯

  • 性能最優化的寫法
//循環優化大串聯
    var i;  //優化變量聲明
    var divs = document.getElementsByTagName("div");
    for(i=divs.length-1; i>=0; i-=1){  
    //優化循環中動態集合讀取、減值迭代、用i-=1 代替 i--
    ...
    }
  • 以優化性能的前提下兼顧可讀性
//合理的循環優化
    var i,len;  //優化變量聲明
    var divs = document.getElementsByTagName("div");
    for(i=0, len = divs.length; i<len; i++){  
    //優化循環中動態集合讀取,必要時也能夠用i+=1 代替 i++
    ...
    }

參考資料

  1. 性能比較工具
  2. JS幾種數組遍歷方式以及性能分析對比
  3. 高性能JavaScript 循環語句和流程控制
  4. Javascript的循環優化探究
相關文章
相關標籤/搜索