JavaScript中哪種型別的迴圈最快?幾種for迴圈對比

2021-07-21 13:00:36

JavaScript 是 Web 開發領域的「常青樹」。無論是 JavaScript 框架(如 Node.js、React、Angular、Vue 等),還是原生 JavaScript,都擁有非常龐大的粉絲基礎。我們來談談現代 JavaScript 吧。迴圈一直是大多數程式語言的重要組成部分,而現代 JavaScript 為我們提供了許多迭代或迴圈值的方法。

但問題在於,我們是否真的知道哪種迴圈或迭代最適合我們的需求。for 迴圈有很多變形,例如 forfor(倒序)、for…offorEachfor…infor…await。本文將圍繞這些展開討論。

瞭解哪一種 for 迴圈或迭代器適合我們的需求,防止我們犯下一些影響應用效能的低階錯誤。

究竟哪一種迴圈更快?

答案其實是: for(倒序)

最讓我感到驚訝的事情是,當我在本地計算機上進行測試之後,我不得不接受 for(倒序)是所有 for 迴圈中最快的這一事實。下面我會舉個對一個包含超過一百萬項元素的陣列執行一次迴圈遍歷的例子。

宣告console.time() 結果的準確度在很大程度上取決於我們執行測試的系統設定。你可以在此處對準確度作進一步瞭解。

const million = 1000000; 
const arr = Array(million);

// 注:這是稀疏陣列,應該為其指定內容,否則不同方式的迴圈對其的處理方式會不同:
// const arr = [...Array(million)]

console.time('⏳');
for (let i = arr.length; i > 0; i--) {} // for(倒序)  :- 1.5ms
for (let i = 0; i < arr.length; i++) {} // for          :- 1.6ms
arr.forEach(v => v)                     // foreach      :- 2.1ms
for (const v of arr) {}                 // for...of     :- 11.7ms
console.timeEnd('⏳');

造成這樣結果的原因很簡單,在程式碼中,正序和倒序的 for 迴圈幾乎花費一樣的時間,僅僅相差了 0.1 毫秒。原因是,for(倒序)只需要計算一次起始變數 let i = arr.length,而在正序的 for 迴圈中,它在每次變數增加後都會檢查條件 i<arr.length。這個細微的差別不是很重要,你可以忽略它。(譯者注:在資料量小或對時間不敏感的程式碼上,我們大可忽略它,但是根據譯者的測試,當資料量擴大,例如十億,千億等的數量級,差距就顯著提升,我們就需要考慮時間對應用程式效能的影響了。)

forEachArray 原型的一個方法,與普通的 for 迴圈相比,forEachfor…of 需要花費更多的時間進行陣列迭代。(譯者注:但值得注意的是,for…offorEach 都從物件中獲取了資料,而原型並沒有,因此沒有可比性。)

迴圈的型別,以及我們應該在何處使用它們

1. For 迴圈(正序和倒序)

我想,也許大家都應該對這個基礎迴圈非常熟悉了。我們可以在任何我們需要的地方使用 for 迴圈,按照核定的次數執行一段程式碼。最基礎的 for 迴圈執行最迅速的,那我們每一次都應該使用它,對嗎?並不然,效能不僅僅只是唯一尺度,程式碼可讀性往往更加重要,就讓我們選擇適合我們應用程式的變形即可。

2. forEach

這個方法需要接受一個回撥函數作為輸入引數,遍歷陣列的每一個元素,並執行我們的回撥函數(以元素本身和它的索引(可選引數)作為引數賦予給回撥函數)。forEach 還允許在回撥函數中使用一個可選引數 this

const things = ['have', 'fun', 'coding'];
const callbackFun = (item, idex) => {
    console.log(`${item} - ${index}`);
}
things.foreach(callbackFun); 
/* 輸出   have - 0
        fun - 1
        coding - 2 */

需要注意的是,如果我們要使用 forEach,我們不能使用 JavaScript 的短路運運算元(||、&&……),即不能在每一次迴圈中跳過或結束迴圈。

3. for…of

for…of 是在 ES6(ECMAScript 6)中實現標準化的。它會對一個可迭代的物件(例如 arraymapsetstring 等)建立一個迴圈,並且有一個突出的優點,即優秀的可讀性。

const arr = [3, 5, 7];
const str = 'hello';
for (let i of arr) {
   console.log(i); // 輸出 3, 5, 7
}
for (let i of str) {
   console.log(i); // 輸出 'h', 'e', 'l', 'l', 'o'
}

需要注意的是,請不要在生成器中使用 for……of,即便 for……of 迴圈提前終止。在退出迴圈後,生成器被關閉,並嘗試再次迭代,不會產生任何進一步的結果。

4. for in

for…in 會在物件的所有可列舉屬性上迭代指定的變數。對於每個不同的屬性,for…in 語句除返回數位索引外,還將返回使用者定義的屬性的名稱。 因此,在遍歷陣列時最好使用帶有數位索引的傳統 for 迴圈。 因為 for…in 語句還會迭代除陣列元素之外的使用者定義屬性,就算我們修改了陣列物件(例如新增自定義屬性或方法),依然如此。

const details = {firstName: 'john', lastName: 'Doe'};
let fullName = '';
for (let i in details) {
    fullName += details[i] + ' '; // fullName: john doe
}

for…offor…in

for…offor…in 之間的主要區別是它們迭代的內容。for…in 迴圈遍歷物件的屬性,而 for…of 迴圈遍歷可迭代物件的值。

let arr= [4, 5, 6];
for (let i in arr) {
   console.log(i); // '0', '1', '2'
}
for (let i of arr) {
   console.log(i); // '4', '5', '6'
}

2.png

結論

  • for 最快,但可讀性比較差
  • foreach 比較快,能夠控制內容
  • for...of 比較慢,但香
  • for...in 比較慢,沒那麼方便

最後,給你一條明智的建議 —— 優先考慮可讀性。尤其是當我們開發複雜的結構程式時,更需要這樣做。當然,我們也應該專注於效能。儘量避免增添不必要的、多餘的花哨程式碼,因為這有時可能對你的程式效能造成嚴重影響。祝你編碼愉快。

譯者注

在譯者的實際測試中,發現:

  • 不同瀏覽器甚至不同版本,結果會有不一樣(顛倒,例如 Firefox 對原生 for-loop 似乎不太友好,Safari 極度喜歡 while)
  • 不同平臺作業系統處理器,結果會有不一樣

英文原文地址:https://medium.com/javascript-in-plain-english/which-type-of-loop-is-fastest-in-javascript-ec834a0f21b9

原文作者:kushsavani

本文轉載自:https://juejin.cn/post/6930973929452339213

譯者:霜羽 Hoarfroster

更多程式設計相關知識,請存取:!!

以上就是JavaScript中哪種型別的迴圈最快?幾種for迴圈對比的詳細內容,更多請關注TW511.COM其它相關文章!