本文 AI 產出,尚未審核

JavaScript 控制流程:跳出與繼續(break / continue


簡介

在日常的程式開發中,我們常會使用迴圈(forwhiledo…while)來處理大量資料或重複性的任務。雖然迴圈本身已經提供了 自動遞增/遞減條件判斷 的功能,但在實務上,我們往往需要在特定情況下提前結束迴圈,或是跳過本次迭代而直接進入下一輪。這時,breakcontinue 就成為了不可或缺的利器。

  • break:立即 跳出 目前所在的迴圈(或 switch),不再執行後續的迭代程式碼。
  • continue略過 本次迭代剩餘的程式碼,直接進入下一輪的迴圈條件判斷。

掌握這兩個關鍵字,能讓你的程式碼更具可讀性、避免不必要的計算,亦能在錯誤處理、資料過濾等情境中提升效能與維護性。


核心概念

1. break 的基本用法

break 只能作用於最內層的迴圈(或 switch),一旦執行,迴圈即刻結束,控制權會回到迴圈外的第一行程式。

// 範例 1:尋找第一個符合條件的數字,找到即停止搜尋
const numbers = [3, 7, 12, 5, 9];
let firstEven = null;

for (let i = 0; i < numbers.length; i++) {
  if (numbers[i] % 2 === 0) {
    firstEven = numbers[i];
    break;               // 找到偶數後直接跳出迴圈
  }
}
console.log(firstEven); // => 12

重點break 只會結束當前迴圈,若有巢狀迴圈,外層迴圈仍會繼續執行。


2. continue 的基本用法

continue 會略過本次迭代剩餘的程式碼,直接回到迴圈條件判斷(for 會執行遞增/遞減表達式,while 會重新檢查條件)。

// 範例 2:過濾掉所有負數,只列印正數
const values = [4, -1, 7, -3, 0, 5];

for (let i = 0; i < values.length; i++) {
  if (values[i] < 0) {
    continue;            // 負數直接跳過,不執行 console.log
  }
  console.log(values[i]); // 只會印出 4, 7, 0, 5
}

提醒continue 不會改變迴圈變數的遞增/遞減,若手動改變變數,請特別留意。


3. 巢狀迴圈中的 breakcontinue

在多層迴圈裡,breakcontinue 預設只影響最內層。若想要跳出更外層的迴圈,需要使用標籤(label)

// 範例 3:找出多維陣列中第一個符合條件的元素,並直接結束所有迴圈
outerLoop:            // 標籤名稱
for (let i = 0; i < matrix.length; i++) {
  for (let j = 0; j < matrix[i].length; j++) {
    if (matrix[i][j] === target) {
      console.log(`找到於 (${i}, ${j})`);
      break outerLoop; // 跳出 outerLoop 所標示的外層迴圈
    }
  }
}

同理,continue 也可以搭配標籤,讓程式直接進入外層迴圈的下一輪:

// 範例 4:在外層迴圈中,只要內層找到特定值,就直接跳到外層的下一次迭代
outer: 
for (let i = 0; i < groups.length; i++) {
  for (let item of groups[i]) {
    if (item === skipValue) {
      continue outer; // 直接進入外層迴圈的下一次
    }
    console.log(item);
  }
}

注意:標籤的使用要適度,過度濫用會降低程式可讀性。僅在真的需要「跳出多層」的情況下使用。


4. breakcontinueswitch 中的角色

switch 陳述式本身也支援 break,用來結束當前的 case,防止「fall‑through」到下一個 case。若忘記 break,JavaScript 會自動執行後續的程式碼,這在某些情況下是刻意的,但大多數時候會造成 bug。

// 範例 5:使用 switch 判斷星期,忘記 break 會導致所有後續 case 都被執行
function getDayMessage(day) {
  switch (day) {
    case 0:
      return "今天是星期日";
    case 1:
      return "今天是星期一";
    case 2:
      return "今天是星期二";
    // ... 省略其他 case
    default:
      return "未知的日期";
  }
}

如果你真的想要 故意 讓程式「穿透」到下一個 case,可以省略 break,或使用 /* falls through */ 註解表明意圖。


5. 何時使用 breakcontinue 以及何時避免

情境 建議使用 為什麼
需要提前結束迴圈(如找到目標、發現錯誤) break 可減少不必要的迭代,提高效能
跳過特定條件的處理,仍需繼續迴圈 continue 讓程式碼更直觀,避免多層 if 包裹
多層迴圈需要一次性結束外層 標籤+break 直接跳出,不必使用額外變數或 flag
只想略過外層迴圈的當前次數 標籤+continue 同上,保持程式流程清晰
迴圈內部有大量副作用(I/O、API 呼叫) 謹慎使用 continue 確保副作用不會被意外跳過
需要保證每個 case只執行一次 break(在 switch 中) 防止「fall‑through」錯誤

常見陷阱與最佳實踐

1. 忘記在 switch 中加 break

最常見的錯誤是忘記在每個 case 後加入 break,導致程式執行意外的「穿透」:

switch (status) {
  case 200:
    console.log('成功');
    // missing break -> 會繼續執行下一個 case
  case 404:
    console.log('找不到資源');
    break;
}

解法:養成 每個 case 結尾加 break 的習慣,或使用 ESLint 規則 no-fallthrough 來自動檢查。


2. 在 whiledo…while 中使用 continue 時遺漏遞增

let i = 0;
while (i < 10) {
  i++;               // 必須先遞增,否則可能陷入無限迴圈
  if (i % 2 === 0) continue;
  console.log(i);
}

若把 i++ 放在 continue 後面,會造成 無限迴圈,因為 continue 會直接跳過遞增語句。

最佳實踐:在 while/do…while 中,將遞增/遞減語句放在迴圈開頭條件檢查前,以免遺漏。


3. 濫用標籤(label)導致程式難以追蹤

標籤語法本身是合法的,但過度使用會讓程式流程變得不直觀。建議:

  • 僅在必須一次性退出多層迴圈時使用。
  • 若可以改用 旗標變數found = true; break;)或 函式抽離,則盡量避免使用標籤。

4. continue 可能會跳過 finally 區塊中的清理工作

try…catch…finally 結構中,continue 仍會執行 finally,但若在 finally 中再次使用 continuebreak,會覆寫原先的控制流,造成難以預期的行為。最好只在 trycatch 中使用 continuefinally 只負責資源釋放。


5. break 不能用於 functionifswitch 之外的區塊

有時候開發者誤以為 break 可以跳出 if 區塊,結果會拋出 SyntaxError。正確做法是使用 函式return 來結束流程。

if (condition) {
  break; // ❌ SyntaxError
}

實際應用場景

1. 搜尋與過濾:找出符合條件的第一筆資料

在大量資料中,只需要第一筆符合條件的結果時,break 能立即停止搜尋,降低時間複雜度。

function findFirstLongWord(words) {
  for (const w of words) {
    if (w.length > 10) return w; // 直接 return 也是一種 break
  }
  return null;
}

2. 表單驗證:遇到錯誤即時終止檢查

function validateForm(fields) {
  for (const field of fields) {
    if (!field.value) {
      alert(`欄位 ${field.name} 必填`);
      break; // 停止後續驗證,避免重複彈窗
    }
  }
}

3. 分頁抓取 API:跳過已處理的頁面

當抓取多頁資料時,若某頁已經在快取中,可使用 continue 略過不必要的請求。

for (let page = 1; page <= totalPages; page++) {
  if (cache.has(page)) continue; // 已快取,直接進入下一頁
  const data = await fetchPage(page);
  cache.set(page, data);
}

4. 遊戲開發:碰撞偵測的早期退出

在大量敵人或子彈的碰撞檢測中,一旦發現碰撞,即可 break 離開迴圈,避免多餘的計算。

for (let i = 0; i < enemies.length; i++) {
  if (player.isColliding(enemies[i])) {
    player.takeDamage();
    break; // 只處理第一個碰撞即可
  }
}

5. 資料清理:過濾掉不合法的紀錄

const clean = [];
for (const row of rawData) {
  if (!row.id) continue; // 沒有 ID 的直接跳過
  clean.push(row);
}

總結

  • break 用於立即結束迴圈或 switch,適合「找到目標」或「發現錯誤」的情境。
  • continue 用於略過本次迭代,常用於「過濾條件」或「跳過不需要的計算」。
  • 標籤(label)可以讓 break/continue 作用於外層迴圈,但應謹慎使用,避免程式難以追蹤。
  • 常見錯誤包括 忘記 break、在 while遺漏遞增、以及 濫用標籤。使用 ESLint單元測試清晰的註解 能有效降低這些風險。
  • 在實務開發中,breakcontinue 不僅能提升效能,更能讓程式邏輯更貼近業務需求:搜尋、驗證、分頁抓取、遊戲碰撞偵測、資料清理等皆是典型應用。

掌握好這兩個關鍵字,你的 JavaScript 程式碼將會變得更簡潔、更高效,也更易於維護。祝你在寫程式的路上,玩得開心、寫得順利! 🚀