學寫提升性能的代碼之流程控制-3

這是我參與8月更文挑戰的第9天,活動詳情查看: 8月更文挑戰編程

前言

業務代碼開發多了,其實就是在寫 if-else數組

與條件判斷相比,循環語句對程序執行性能的影響更大。一個循環語句的循環執行次數直接影響程序的時間複雜度,若是代碼中還存在缺陷致使循環不能及時中止,從而形成死循環,那麼給用戶帶來的使用體驗將會是很是糟糕的。本文記錄,怎樣編寫循環語句能對性能產生有益的影響。markdown


三種常規循環語句

JavaScript中循環語句的常見寫法有三種,第一種是標準的for循環,這與大部分編程語言相似,包括初始化、循環結束條件、迭代語句及循環體四部分,代碼示例以下:數據結構

// 標準for循環
for(let i = 0; i < length; i ++){
  // 循環體
}
複製代碼

第二種和第三種分別是while循環和do-while循環,兩者惟一的差異就是do-while循環會先執行一遍循環體,再去判斷循環結束條件,代碼示例以下:app

// while循環
let i = 0
while(i < length){
  // 循環體
  i ++
}
// do-while 循環
do {
  // 循環體
  i ++
} while (i < length)
複製代碼

一般在使用這三種循環語句時,基本場景都是對數組元素進行遍歷。從索引的第一個元素開始直到數組的最後一個元素結束,每次在執行循環判斷時,都須要將當前的數組索引與數組長度進行比較。因爲該比較操做執行的過程當中數組長度通常不會改變,且存取局部變量要比查找屬性值更省時,因此提早將要遍歷的數組長度聲明爲局部變量,而後將該局部變量進行循環結束的條件判斷,效率會更高一些。下面以for循環爲例:編程語言

// 較差的循環結束判斷
const array = [1,2,3,4,5]
for(let i = 0; i < array.length; i ++){
  // 省略循環體過程
}
// 較好的循環結束判斷
const len = array.length
for(let i = 0; i < len; i ++){
  // 省略循環體過程
}
複製代碼

這在對包含較大規模DOM節點數的遍歷過程當中,效果會更加明顯。此外還有一種更簡單的提高循環語句性能的方式:將循環變量遞減到0,而非遞增到數組總長度ide

// 更好的循環結束判斷
for(let i = arr.length - 1; i > 0; i --){
  // 省略循環體過程
}
複製代碼

由於循環結束的判斷是和常量0進行比較的,不存在對數組長度屬性值的查找或局部變量的讀取,其比較的運算速度會更快。因爲三種循環語句的執行性能基本相似,因此僅針對結束條件的判斷進行優化。函數

for-in循環與函數迭代

for-in可用來遍歷JavaScript對象的可枚舉屬性,一般用法以下:post

// 遍歷object對象的全部屬性
for(let prop in object){
  // 確保不會遍歷到object原型鏈上的其餘對象
  if(object.hasOwnProperty(prop)){
    // 相關屬性的處理過程
  }
}
複製代碼

能夠看出for−in循環可以遍歷對象的屬性集,特別適合處理諸如JSON對象這樣的未知屬性集,但對一般的循環使用場景來講,因爲它遍歷屬性的順序不肯定,循環的結束條件也沒法改變,而且由於須要從目標對象中解析出每一個可枚舉的屬性,即要檢查對象的原型和整個原型鏈,因此其循環速度也會比其餘循環方式要慢許多,若是循環性能有要求則儘可能不要使用for−in循環。性能

另外對於數組的循環,JavaScrpt原生提供了一種forEach函數選代的方法,此方法會遍歷數組上的全部元素,並對每一個元素執行一個方法,所運行的方法做爲forEach函數的入參,代碼以下:

//對數組進行函數選代  
myArray.forEach((value, index, arr) => {
  // 可處理數組中的每一個元素
})
複製代碼

這種方法使用起來的確會讓數組元素的迭代看起來更加直觀,但在一般狀況下與三種基本的循環方法相比,其性能方面僅能達到後者的1/8,若是數組長度較大或對運行速度有比較嚴格的要求,則函數迭代的方式不建議使用。

同時還有一種for語句的變形,就是ES6加入的for−of循環,咱們可使用它來代替for-in和forEach循環,它不只在性能方面比這兩者更好,而且還支持對任何可選迭代的數據結構進行遍歷,好比數組、字符串、映射和集合,但與三種常規循環語句相比其性能仍是稍遜色一些的。

相關文章
相關標籤/搜索