JavaScript 控制流程:跳出與繼續(break / continue)
簡介
在日常的程式開發中,我們常會使用迴圈(for、while、do…while)來處理大量資料或重複性的任務。雖然迴圈本身已經提供了 自動遞增/遞減 與 條件判斷 的功能,但在實務上,我們往往需要在特定情況下提前結束迴圈,或是跳過本次迭代而直接進入下一輪。這時,break 與 continue 就成為了不可或缺的利器。
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. 巢狀迴圈中的 break 與 continue
在多層迴圈裡,break 與 continue 預設只影響最內層。若想要跳出更外層的迴圈,需要使用標籤(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. break 與 continue 在 switch 中的角色
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. 何時使用 break、continue 以及何時避免
| 情境 | 建議使用 | 為什麼 |
|---|---|---|
| 需要提前結束迴圈(如找到目標、發現錯誤) | 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. 在 while 或 do…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 中再次使用 continue 或 break,會覆寫原先的控制流,造成難以預期的行為。最好只在 try 或 catch 中使用 continue,finally 只負責資源釋放。
5. break 不能用於 function、if 或 switch 之外的區塊
有時候開發者誤以為 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、單元測試 與 清晰的註解 能有效降低這些風險。 - 在實務開發中,
break與continue不僅能提升效能,更能讓程式邏輯更貼近業務需求:搜尋、驗證、分頁抓取、遊戲碰撞偵測、資料清理等皆是典型應用。
掌握好這兩個關鍵字,你的 JavaScript 程式碼將會變得更簡潔、更高效,也更易於維護。祝你在寫程式的路上,玩得開心、寫得順利! 🚀