自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

JavaScript 循環(huán):擁有最佳性能的最佳實踐

譯文 精選
開發(fā) 前端
這篇文章介紹了 JavaScript 中各種循環(huán)語句的特點和性能,以及如何根據(jù)不同的場景選擇合適的循環(huán)方式。文章通過一些實例和測試,給出了一些使用循環(huán)的最佳實踐,如避免不必要的計算、使用緩存變量、使用 break 和 continue 等。

譯者 | 劉汪洋

審校 | 重樓

概括:這篇文章介紹了 JavaScript 中各種循環(huán)語句的特點和性能,以及如何根據(jù)不同的場景選擇合適的循環(huán)方式。文章通過一些實例和測試,給出了一些使用循環(huán)的最佳實踐,如避免不必要的計算、使用緩存變量、使用 break 和 continue 等。

介紹

循環(huán)是編程語言的基本組成部分,在 JavaScript 中也同樣不可或缺。JavaScript 循環(huán)是一種功能強大的編程工具,它讓開發(fā)者能夠遍歷數(shù)據(jù)集合,針對每個項目執(zhí)行特定操作,并根據(jù)具體條件作出決策。

然而,實現(xiàn)方式不當可能導(dǎo)致負面問題。編寫錯誤的循環(huán)不僅可能引發(fā)性能問題和編程錯誤,還可能使代碼變得難以維護。
無論你是編程新手還是有豐富經(jīng)驗的開發(fā)人員,編寫高效且合理的循環(huán)總是一項充滿挑戰(zhàn)的任務(wù)。

在本全面指南中,我們將詳細探討編寫 JavaScript 循環(huán)的最佳實踐,助你將代碼從新手水平提升至專家水平。我們將從最基本的部分開始,涵蓋如何選擇正確的循環(huán)類型和優(yōu)化循環(huán)性能等方面。
后面,我們還將深入探討更高級的主題,包括如何運用函數(shù)式編程技巧,以及如何在處理異步循環(huán)時保持謹慎,以避免代碼運行時出現(xiàn)不可預(yù)見的情況。

不論你是使用 數(shù)組、對象 還是其他數(shù)據(jù)結(jié)構(gòu),我們所分享的技巧和方法都將有助于你編寫干凈、簡潔且無 bug 的循環(huán)代碼。
因此,如果你準備深入了解 JavaScript 循環(huán)的精髓,那就做好準備,讓我們共同探索吧!

選擇正確類型的循環(huán)

在 JavaScript 編程中,選擇合適的循環(huán)類型很關(guān)鍵。JavaScript 提供了幾種主要的循環(huán)類型,包括 for 循環(huán)、while 循環(huán)do-while 循環(huán),每種類型都有其適用場景及優(yōu)缺點。

For 循環(huán)

For 循環(huán)是 JavaScript 中最常用的循環(huán)類型,特別適用于在已知循環(huán)次數(shù)的情況。
例如,要計算數(shù)字數(shù)組的和:

let numbers = [1, 2, 3, 4, 5];
let sum = 0;
for (let i = 0; i < numbers.length; i++) {
  sum += numbers[i];
}
console.log(sum); // 輸出:15

在此示例中,for 循環(huán)遍歷數(shù)組的每個元素并累加其值。

While 循環(huán)

While 循環(huán)適用于重復(fù)執(zhí)行代碼塊直到滿足某條件的場景。
例如,生成大于 0.5 的隨機數(shù):

let randomNumber = Math.random();
while (randomNumber <= 0.5) {
  randomNumber = Math.random();
}
console.log(randomNumber); // 輸出:大于 0.5 的數(shù)字

此例中,while 循環(huán)不斷生成新的隨機數(shù),直到滿足條件。

Do-While 循環(huán)

Do-while 循環(huán)與while 循環(huán)相似,但無論初始條件如何,至少會執(zhí)行一次代碼塊。
例如,要求用戶輸入一個介于 1 和 10 之間的數(shù)字:

let number;
do {
  number = prompt('輸入一個介于 1 和 10 之間的數(shù)字:');
} while (number < 1 || number > 10);
console.log(number); // 輸出:介于 1 和 10 之間的數(shù)字

此例中,do-while 循環(huán)反復(fù)提示用戶輸入合法數(shù)字。
選擇合適的循環(huán)類型取決于具體需求和任務(wù)。如果已知執(zhí)行次數(shù),通常選擇 for 循環(huán);如果需要滿足某個條件才停止執(zhí)行,則 while 循環(huán)或 do-while 循環(huán)可能更合適。通過慎重選擇循環(huán)類型,可以使代碼執(zhí)行更高效、更易于理解。

循環(huán)控制語句的正確使用

選擇了合適的循環(huán)結(jié)構(gòu)后,你還需要深入了解如何在 JavaScript 中正確運用兩種主要的循環(huán)控制語句:break 和 continue。
這兩種控制語句可以讓你更靈活地控制循環(huán)的執(zhí)行流程。當滿足特定條件時,break 語句用于完全終止循環(huán),而 continue 語句則用于跳過當前迭代并進入下一個迭代。
例如,設(shè)有一個數(shù)字數(shù)組,你想通過 for 循環(huán)找到數(shù)組中的第一個偶數(shù)數(shù)字。一旦找到第一個偶數(shù),你可以使用 break 語句退出循環(huán):

const numbers = [1, 3, 2, 5, 4, 7, 6];
for (let i = 0; i < numbers.length; i++) {
  if (numbers[i] % 2 === 0) {
    console.log(`第一個偶數(shù)是 ${numbers[i]}`);
    break;
  }
}

在這個例子中,一旦找到第一個偶數(shù)(即 2),循環(huán)就會終止。如果沒有 break 語句,循環(huán)會繼續(xù)遍歷數(shù)組的其余部分。
相對于上述情況,如果你想在數(shù)組中打印所有的奇數(shù),并跳過所有偶數(shù),可以使用 continue 語句:

const numbers = [1, 3, 2, 5, 4, 7, 6];
for (let i = 0; i < numbers.length; i++) {
  if (numbers[i] % 2 === 0) {
    continue;
  }
  console.log(`奇數(shù):${numbers[i]}`);
}

在這個例子中,循環(huán)會跳過偶數(shù),僅打印奇數(shù)(即 1、3、5 和 7)。如果沒有 continue 語句,循環(huán)將會打印數(shù)組中的所有數(shù)字。
如今,我們已經(jīng)掌握了如何為特定任務(wù)選擇適當?shù)难h(huán),以及何時使用 break 和 continue 語句。
下一步我們將探討的是編寫循環(huán)時需考慮的另一個重要方面:優(yōu)化循環(huán)性能。

優(yōu)化循環(huán)的性能

在日常編碼過程中,循環(huán)性能的優(yōu)化可能不會引起太多關(guān)注。但是當面臨大數(shù)據(jù)處理時,循環(huán)性能的提高就成為了關(guān)鍵任務(wù),因為它會對整個 JavaScript 代碼的性能產(chǎn)生決定性影響。因此,了解如何分析和增強循環(huán)性能變得至關(guān)重要。
以下是一些關(guān)于如何優(yōu)化循環(huán)性能的實用建議:

避免不必要的計算

一個提高循環(huán)性能的常見方法是減少不必要的計算。為了讓這一點更加明確,我們可以參考下述示例:
假設(shè)你正在對一個名為 array 的數(shù)組進行迭代。在這種場景下,如果你使用 for 循環(huán)遍歷數(shù)組,每一次的迭代都會重新計算數(shù)組的 length 以確定是否應(yīng)繼續(xù)循環(huán)。
以下列代碼為例:

let arr = [1, 2, 3, 4, 5];
for (let i = 0; i < arr.length; i++) { 
  console.log(arr[i]); 
}

在每次迭代中,系統(tǒng)都會檢測 i 是否小于數(shù)組長度。但如果數(shù)組非常龐大,每次重新獲取長度可能會成為性能瓶頸。注意:JavaScript 中的數(shù)組是特殊的對象,能夠容納各種數(shù)據(jù)類型。每個數(shù)組都帶有一個 length 屬性,反映了其元素數(shù)量,且會隨著元素的增減自動更新。

為了改善性能,你可以在循環(huán)外部將數(shù)組的 length 存儲為一個變量:

let arr = [1, 2, 3, 4, 5];
let len = arr.length; // 緩存長度
for (let i = 0; i < len; i++) { 
  console.log(arr[i]); 
}

這樣做可以避免在每次迭代中都訪問數(shù)組的 length 屬性,從而顯著提高代碼的運行效率。對于處理大型數(shù)組,這個技巧可能特別有效。
注意:現(xiàn)代 JavaScript 引擎(如 V8)已經(jīng)高度優(yōu)化了循環(huán)。因此,有時緩存數(shù)組的長度可能不會顯著提升性能。不過,作為良好編程實踐,特別是在處理大型數(shù)組或性能敏感代碼時,這種技巧依然有價值。

高效循環(huán)的應(yīng)用

采用高效的循環(huán)結(jié)構(gòu)來提升循環(huán)性能是一項重要手段。
例如,在數(shù)組遍歷過程中,for 循環(huán)通常具有比 forEach 循環(huán)更高的執(zhí)行效率。
以下代碼片段可以讓我們深入理解這一觀點:

let arr = [1, 2, 3, 4, 5]; // 使用 for 循環(huán)遍歷數(shù)組
for (let i = 0, len = arr.length; i < len; i++) { 
  console.log(arr[i]); 
}

在此例中,我們采用 for 循環(huán)來遍歷 arr 數(shù)組,但同樣的效果可以通過 forEach 循環(huán)實現(xiàn)。

那么,for 循環(huán)為何具有更高的執(zhí)行效率呢?

這個問題較為復(fù)雜,有許多細節(jié)值得深入探討。其中一個關(guān)鍵原因是,forEach 循環(huán)會為數(shù)組的每個元素創(chuàng)建一個新的函數(shù)作用域。

換言之,每個元素都會生成一個新的函數(shù),并在迭代結(jié)束后將其銷毀。

對于小型數(shù)組,這一過程影響不大。但是,當處理大型數(shù)組時,它可能會對循環(huán)的執(zhí)行速度產(chǎn)生負面影響。

與之相對,for 循環(huán)只為整個循環(huán)過程創(chuàng)建一次函數(shù)作用域,因此僅需要創(chuàng)建并銷毀一個函數(shù)作用域。

另外,for 循環(huán)還支持使用 break 和 continue 來靈活控制循環(huán)的迭代過程,而 forEach 循環(huán)則無法實現(xiàn)這一功能。

正因如此,for 循環(huán)在數(shù)組遍歷時具備更高的優(yōu)化潛力。

DOM 操作的最小化

在循環(huán)過程中,減少對文檔對象模型(DOM)的操作至關(guān)重要,因為在 JavaScript 中,與 DOM 的交互通常是一個耗時的過程。
每一次更改 DOM 都會讓瀏覽器重新布局和繪制頁面,可能降低應(yīng)用程序的執(zhí)行速度,特別是處理大量元素時。
例如:

// 低效的 DOM 操作 
for (let i = 0; i < 1000; i++) { 
  document.getElementById('myDiv').innerHTML += '<p>' + i + '</p>'; 
} 
// 更高效的 DOM 操作 
let output = ''; 
for (let i = 0; i < 1000; i++) { 
  output += '<p>' + i + '</p>'; 
} 
document.getElementById('myDiv').innerHTML = output;

在上述例子中,第一個循環(huán)效率較低,因為每次迭代都直接操作 DOM。每次迭代都會給 myDiv 元素的 innerHTML 屬性添加新段落,導(dǎo)致了 1000 次 DOM 操作。

與此相反,第二個循環(huán)的效率更高,原因在于它減少了對 DOM 的直接操作。循環(huán)并不是在每次迭代時都更新 DOM,而是將 HTML 字符串累加到名為 output 的變量中。一旦循環(huán)完成,就使用 output 字符串僅一次更新 myDiv 元素的 innerHTML 屬性,從而實現(xiàn)了只進行一次 DOM 操作,大大提高了效率。

規(guī)避常見錯誤

在使用 JavaScript 編程時,開發(fā)人員可能會遇到一些典型的錯誤。以下要探討的這些錯誤在實際編程中應(yīng)引起警覺,并積極規(guī)避。

循環(huán)內(nèi)部改動循環(huán)變量

在循環(huán)內(nèi)部更改循環(huán)變量可能引發(fā)預(yù)期不到的效果或錯誤。此做法通常并不合適。理想的方案是使用一個單獨的變量來存儲你希望更改的值。
例如,如下循環(huán):

for (let i = 0; i < 10; i++) { 
  console.log(i); i++; // 在循環(huán)內(nèi)修改 i 
}

上述代碼中,i 在循環(huán)中被修改,可能造成不在期望范圍的結(jié)果。相對地,你應(yīng)該像下面這樣使用一個單獨的變量來存儲你想要修改的值:

for (let i = 0; i < 10; i++) { 
  console.log(i); 
  let modifiedValue = i + 1; // 使用一個單獨的變量來修改 i 
}

忽略大括號的使用

雖然你可以在編寫循環(huán)時省略大括號,但這通常并不推薦。缺少大括號可能復(fù)雜化代碼的閱讀和理解,甚至可能引發(fā)錯誤或不預(yù)期的效果。
例如,如下循環(huán):

for (let i = 0; i < 10; i++) 
  console.log(i);

由于此循環(huán)未使用大括號,可能使代碼的閱讀和理解變得困難,因此即使是單行語句,也最好始終使用大括號:

for (let i = 0; i < 10; i++) { 
  console.log(i); 
}

避免無限循環(huán)

無限循環(huán)指的是永不終止的循環(huán)。當退出條件設(shè)置不當,或永不滿足時,就可能出現(xiàn)這種情況。無限循環(huán)不僅可能導(dǎo)致程序崩潰或掛起,還可能非常難以調(diào)試。
例如:
觀察下面的循環(huán),它沒有增加變量值,也未檢查是否超過某個閾值:

let count = 0; 
while (count < 10) { 
  console.log(count); 
}

由于 count 變量未曾增加,此代碼將觸發(fā)無限循環(huán)。
因此,你應(yīng)該時刻警惕無限循環(huán)的可能性。為了避免無限循環(huán),請確保設(shè)置了正確的退出條件,并對代碼進行了充分測試。

“越界”錯誤

在編程中,越界錯誤是一種常見問題,發(fā)生在使用不正確的比較運算符或未充分考慮循環(huán)變量初始值的情況下。這些錯誤可能導(dǎo)致程序結(jié)果不準確,甚至在某些情況下會觸發(fā)程序崩潰。
例如,假設(shè)你有一個包含 10 個元素的數(shù)組,你計劃遍歷它,并對每個元素執(zhí)行特定操作。
正確的循環(huán)編寫如下:

const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 
for (let i = 0; i < arr.length; i++) { 
  console.log(arr[i]); 
}

該代碼將遍歷數(shù)組的全部 10 個元素,并將各個元素的值輸出到控制臺。但是,如果你誤用了比較運算符,將 i< arr.length寫成 i<=arr.length會怎樣呢?

const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 
for (let i = 0; i <= arr.length; i++) { 
  console.log(arr[i]); 
}

這段代碼將觸發(fā)一個越界錯誤,因為當i等于 arr.length時,將嘗試訪問一個不存在的元素。循環(huán)將執(zhí)行共計11 次而非 10 次,最后一次迭代將拋出錯誤,因為 arr[10] 的值為 undefined。為了防止越界錯誤的發(fā)生,你應(yīng)仔細檢查循環(huán)條件、確保使用正確的比較運算符,并充分考慮循環(huán)變量的初始值。通過避免這些常見錯誤,你能夠確保循環(huán)的準確執(zhí)行,從而降低程序中的錯誤或崩潰風險。同時,在執(zhí)行代碼之前,仔細審查潛在錯誤始終是明智的做法。

在適當場合,選擇遞歸

在程序設(shè)計中,遞歸經(jīng)常被視為一種優(yōu)雅的解決方案。
遞歸特別適用于處理層級數(shù)量未知或不固定的分層數(shù)據(jù)結(jié)構(gòu),如樹形結(jié)構(gòu)或嵌套數(shù)組。
與傳統(tǒng)的嵌套循環(huán)相比,當處理具有未知深度的結(jié)構(gòu)時,遞歸能使代碼更整潔、易讀。
警告:使用遞歸時需謹慎,確保遞歸有明確的終止條件,避免發(fā)生無限遞歸和棧溢出錯誤。
例如,考慮以下情景:
假設(shè)你擁有一個包含嵌套數(shù)字的數(shù)組結(jié)構(gòu),你的任務(wù)是找到數(shù)組中所有數(shù)字(包括嵌套的數(shù)字)的總和。在此情景下,遞歸可以被優(yōu)雅地應(yīng)用。下面是一個通過遞歸來求嵌套數(shù)組總和的示例代碼:

const nestedArray = [[1, 2, [3]], 4]; 
function sumArray(arr) { 
  let sum = 0; 
  for (let i = 0; i < arr.length; i++) { 
    if (Array.isArray(arr[i])) { 
      // 如果當前元素是數(shù)組,則遞歸處理
      sum += sumArray(arr[i]); 
    } else { 
      // 如果當前元素是數(shù)字,則加入總和
      sum += arr[i]; 
    } 
  } 
  return sum; 
} 
console.log(sumArray(nestedArray)); // 輸出:10

此代碼利用遞歸深入遍歷嵌套數(shù)組 nestedArray。它可以計算所有數(shù)字的總和,而不受嵌套深度的限制。

遞歸函數(shù)允許自身反復(fù)調(diào)用,直到達到最底層的嵌套結(jié)構(gòu),并返回一個可用于計算最終總和的值。

通過檢查每個元素是否為數(shù)組,該函數(shù)遞歸處理數(shù)組元素,直到達到最深的嵌套層級,即數(shù)字。

然后,函數(shù)將該數(shù)字返回到上一遞歸層。這樣便于計算當前層級所有元素的總和。

通過這種方式,遞歸提供了一種靈活而優(yōu)雅的方法,用于處理未知或不固定層級結(jié)構(gòu)的問題。

結(jié)論

JavaScript 循環(huán)非常重要,但要精通使用它可能有一定的難度。遵循以上最佳實踐,你將能夠編寫更高效、更合理的循環(huán)代碼,進而提升整體的編程水準。
要選擇合適的循環(huán)類型,并準確地使用循環(huán)控制語句來優(yōu)化循環(huán)性能,避免常見的錯誤。同時,在適宜的場景下,你可以考慮遞歸的使用。只要掌握這些技巧,你就能大幅增強自己在 JavaScript 循環(huán)方面的專業(yè)技能。
因此,如果你投入時間來評估和優(yōu)化循環(huán)代碼,你的代碼性能將得到顯著提升。

譯者介紹

劉汪洋,51CTO社區(qū)編輯,昵稱:明明如月,一個擁有 5 年開發(fā)經(jīng)驗的某大廠高級 Java 工程師,擁有多個主流技術(shù)博客平臺博客專家稱號。

原文標題:JavaScript Loop: The Best Practices to Have the Optimal Performance,作者:robiulhr

責任編輯:華軒 來源: 51CTO
相關(guān)推薦

2010-07-06 09:07:09

2011-11-02 12:29:45

2010-02-04 11:55:27

ibmdwDB2

2011-08-11 09:45:25

2018-01-12 14:37:34

Java代碼實踐

2016-06-20 11:32:27

JS原型class

2017-02-06 09:20:23

JavaScript實踐

2017-01-20 09:45:20

JavaScript代碼質(zhì)量

2016-11-17 09:00:46

HBase優(yōu)化策略

2014-03-19 14:34:06

JQuery高性能

2017-03-01 20:53:56

HBase實踐

2023-07-21 01:12:30

Reactfalse?變量

2011-08-18 11:05:21

jQuery

2023-11-12 11:54:55

UX性能widget

2015-09-15 16:01:40

混合IT私有云IT架構(gòu)

2016-12-27 08:49:55

API設(shè)計策略

2013-12-31 09:26:31

JavaScript技巧

2025-04-11 03:00:55

2011-07-22 09:50:34

云服務(wù)云計算

2011-09-20 10:41:45

Web
點贊
收藏

51CTO技術(shù)棧公眾號