在 JavaScript 中的迭代最佳實踐

在 JavaScript 中的迭代最佳實踐

本文將解釋在 JavaScript 中進行迭代的最佳實踐。

YouTube Video

在 JavaScript 中的迭代最佳實踐

在 JavaScript 中,使用 for 迴圈進行迭代非常常見。在此,我們將詳細說明使用 for 迴圈編寫高效且易讀代碼的最佳實踐。

選擇合適的迴圈結構

JavaScript 提供多種迴圈結構,各自適用於不同的用途。

 1// Example of a for loop
 2for (let i = 0; i < 5; i++) {
 3    console.log(i);
 4}
 5
 6// Example of a for...of loop
 7const array = [10, 20, 30];
 8for (const value of array) {
 9    console.log(value);
10}
11
12// Example of a for...in loop
13const obj = { a: 1, b: 2, c: 3 };
14for (const key in obj) {
15    console.log(`${key}: ${obj[key]}`);
16}
17
18// Example of a while loop
19let count = 0;
20while (count < 5) {
21    console.log(count);
22    count++;
23}
  • for 語句 適用於迭代次數已預先確定的情況。
  • for...of 語句 適用於簡潔處理陣列和可迭代物件。
  • for...in 語句 用於迭代物件的屬性。然而,它不適合用於陣列。
  • while 語句do...while 語句 用於根據條件控制迴圈。

使用 forEach 方法和 for...of 語句

當遍歷陣列時,使用 for 語句訪問索引很常見,但 forEach 方法或 for...of 語句可能更易讀。

 1// Using a standard for loop
 2const array = ["apple", "banana", "cherry"];
 3for (let i = 0; i < array.length; i++) {
 4    console.log(array[i]);
 5}
 6
 7// Using forEach
 8array.forEach(item => console.log(item));
 9
10// Using for...of
11for (const item of array) {
12    console.log(item);
13}
  • for 語句 在迭代時允許明確的索引管理。
  • forEach 方法 使用回呼函數簡潔地處理每個元素。
  • for...of 語句 可讀性高,並允許直接訪問陣列中的每個元素。

優化迴圈條件

由於迴圈條件會被多次評估,避免不必要的計算可以提升性能。

 1const names = ["Alice", "Bob", "Charlie"];
 2const scores = [85, 92, 78];
 3
 4// Inefficient example
 5for (let i = 0; i < Math.min(names.length, scores.length); i++) {
 6    console.log(`${names[i]} scored ${scores[i]}`);
 7}
 8
 9// Efficient example
10for (let i = 0, len = Math.min(names.length, scores.length); i < len; i++) {
11    console.log(`${names[i]} scored ${scores[i]}`);
12}
  • 如本例所示,事先將計算結果存儲在變量中,可以更有效率地執行迴圈。
 1const scores = [85, 92, 78];
 2let sum = 0;
 3let sum2 = 0;
 4
 5// Inefficient example
 6for (let i = 0; i < scores.length; i++) {
 7    sum += scores[i];
 8}
 9console.log(`Total score : ${sum}`);
10
11// Efficient example
12for (let i = scores.length - 1; i >= 0; i--) {
13    sum2 += scores[i];
14}
15console.log(`Total score : ${sum2}`);
  • 如本例所示,反轉條件有時候可能會更高效。

優化迴圈處理

由於迴圈處理是反覆執行的,避免不必要的計算可以提升效能。

 1const array = ["apple", "banana", "cherry"];
 2
 3// Inefficient example
 4for (let i = 0; i < 100; i++) {
 5    const element = document.querySelector("#myElement");
 6    element.textContent = `Count: ${i}`;
 7}
 8
 9// Efficient example
10const element = document.querySelector("#myElement");
11for (let i = 0; i < 100; i++) {
12    element.textContent = `Count: ${i}`;
13}
  • 在此例中,將querySelector方法移到迴圈之外,可以消除不必要的重複計算。

注意作用域

使用 letconst 確保迴圈內的變數具有適當的作用域。由於 var 僅限於函數作用域,可能導致意外的行為。

 1// Using let
 2for (let i = 0; i < 3; i++) {
 3    console.log(i);
 4}
 5
 6// Potential issue with var
 7for (var i = 0; i < 3; i++) {
 8    setTimeout(() => console.log(i), 1000); // 3, 3, 3
 9}
10
11// Using let to avoid the issue
12for (let i = 0; i < 3; i++) {
13    setTimeout(() => console.log(i), 1000); // 0, 1, 2
14}
  • var具有函數作用域,因此在迴圈結束後,i值為3,所有由setTimeout執行的函數都輸出3
  • 使用let時,setTimeout回調函數中的i在每次迴圈中都表示一個新值,因此會按預期輸出0, 1, 2

透過早期退出提升可讀性

為簡化迴圈處理,適當使用 breakcontinue 可提升可讀性。

 1// Example using break
 2for (let i = 0; i < 10; i++) {
 3    if (i === 5) {
 4        break; // Exit the loop
 5    }
 6    console.log(i);
 7}
 8
 9// Example using continue
10for (let i = 0; i < 10; i++) {
11    if (i % 2 === 0) {
12        continue; // Skip to the next iteration
13    }
14    console.log(i);
15}
  • 使用break可以在中途終止迴圈處理,跳過所有後續的迭代。
  • 使用continue可以跳過當前的迴圈過程,直接進入下一次迭代。

避免深層嵌套

深層嵌套會使代碼更難閱讀,因此應通過早期返回或將功能拆分為函數來保持嵌套層次淺。

 1// Deeply nested example
 2for (let i = 0; i < 5; i++) {
 3    for (let j = 0; j < 5; j++) {
 4        if (i + j > 5) {
 5            console.log(i, j);
 6        }
 7    }
 8}
 9
10// Improved using function decomposition
11function processPairs(i) {
12    for (let j = 0; j < 5; j++) {
13        if (i + j > 5) {
14            console.log(i, j);
15        }
16    }
17}
18
19for (let i = 0; i < 5; i++) {
20    processPairs(i);
21}
  • 在此例中,使用函數來減少嵌套層次。

考慮錯誤處理

如果在循環中可能發生錯誤,請實施適當的錯誤處理。

 1const data = ["123", "abc", "456", "xyz"];
 2
 3// Without Error Handling
 4for (const item of data) {
 5    const result = parseInt(item);
 6    console.log(`Parsed value: ${result}`);
 7}
 8
 9// With Error Handling
10for (const item of data) {
11    try {
12        const result = parseInt(item);
13        if (isNaN(result)) {
14            throw new Error(`Invalid number: ${item}`);
15        }
16        console.log(`Parsed value: ${result}`);
17    } catch (error) {
18        console.error(`Error processing item: ${item}. ${error.message}`);
19    }
20}
  • 在此例中,對無效數據進行錯誤處理,檢測並報告問題。

處理非同步操作時的注意事項

在處理循環中的非同步操作時,使用 async/await 可以編寫簡潔且直觀的代碼。

 1const urls = ["https://example.com/1", "https://example.com/2"];
 2
 3// Proper handling of asynchronous operations
 4async function fetchUrls() {
 5    for (const url of urls) {
 6        const response = await fetch(url);
 7        const data = await response.json();
 8        console.log(data);
 9    }
10}
11
12fetchUrls();
  • 此代碼會異步地逐個從urls數組中獲取URL,並以JSON格式處理結果。使用async/await簡化了異步操作,依次從每個URL獲取數據並將其輸出到控制台。

了解在非同步處理中,for...of 語句和 forEach() 的差異。

 1async function asyncTask(num) {
 2    return new Promise(resolve => {
 3        setTimeout(() => {
 4            console.log(`Task ${num} done`);
 5            resolve();
 6        }, 100);
 7    });
 8}
 9
10async function runWithForOf() {
11    console.log("Start for...of");
12    for (const num of [1, 2, 3]) {
13        await asyncTask(num);
14    }
15    console.log("End for...of");
16}
17
18async function runWithForEach() {
19    console.log("Start forEach");
20    [1, 2, 3].forEach(async num => {
21        await asyncTask(num);
22    });
23    console.log("End forEach");
24}
25
26async function executeExamples() {
27    await runWithForOf();
28    await runWithForEach();
29}
30
31executeExamples();
  • 當在迴圈中處理非同步時,請注意在使用 for...ofasync/await 和使用 forEach() 時的行為差異,如此範例所示。

  • 使用 for...of 時,程式會依序執行,並在迴圈中的 await 停下來等待,然後才進入下一次迭代。相對地,forEach() 則會平行執行處理。

結論

JavaScript 中的 for 語句是一個簡單但功能強大的工具。透過運用此處介紹的最佳實踐,您可以編寫高效且可讀性高的代碼。注意選擇適當的循環結構、作用域管理、錯誤處理,並以編寫高度可維護的代碼為目標。

您可以在我們的 YouTube 頻道上使用 Visual Studio Code 來跟隨上述文章一起學習。 請也查看我們的 YouTube 頻道。

YouTube Video