本文 AI 產出,尚未審核

JavaScript 控制流程 – 標籤(label)語法

簡介

在 JavaScript 的控制流程裡,我們常會使用 if / elseforwhileswitch 等結構來決定程式的走向。雖然大多數情況下這些語法已足以滿足需求,但在 多層巢狀迴圈深度條件判斷 時,想要直接跳出或重新進入特定的程式區塊,就會變得相當繁瑣。
這時 標籤(label) 便派上用場。標籤本身是一個自訂的名稱,搭配 breakcontinuethrow 使用,讓程式可以精確地控制跳脫的層級,提升可讀性與維護性。

本篇文章將從概念說明、實作範例、常見陷阱到實務應用,完整介紹 JavaScript 中的標籤語法,讓你在需要時能自信地使用它。


核心概念

1. 標籤的基本語法

標籤是由 標籤名稱 + 冒號 組成,必須緊接在可被 breakcontinue 中斷的語句(如迴圈、switch)之前:

labelName: statement
  • labelName 必須是合法的識別字,且在同一作用域內不能重複。
  • 標籤本身不會改變程式的執行結果,除非與 breakcontinuethrow 搭配使用。

2. break label – 跳出指定層級

break 預設會跳出最內層的迴圈或 switch。加上標籤後,break label 會直接跳出 標籤所標示的那一層,即使它不是最內層。

outer: for (let i = 0; i < 5; i++) {
  inner: for (let j = 0; j < 5; j++) {
    if (i + j > 6) break outer; // 直接離開 outer 迴圈
    console.log(i, j);
  }
}

3. continue label – 重新開始指定層級

continue 只對迴圈有效。加上標籤後,continue label 會結束 標籤所指向的那一層迴圈,直接進入下一次迭代。

outer: for (let i = 0; i < 3; i++) {
  for (let j = 0; j < 5; j++) {
    if (j === 2) continue outer; // 跳過剩餘的 inner 迭代,直接 i+1
    console.log(`i=${i}, j=${j}`);
  }
}

4. 標籤與 throw 的結合

雖然 throw 本身會拋出例外,但有時候想要在特定區塊內捕捉例外後立即退出,可以利用標籤配合 try…catch

search: {
  try {
    // 假設有多層搜尋步驟
    step1();
    step2();
    step3();
  } catch (e) {
    console.error('搜尋失敗,直接結束區塊');
    break search; // 結束整個 search 區塊
  }
  console.log('搜尋成功');
}

5. 標籤的作用範圍

標籤的作用域與宣告它的程式區塊相同。若在函式內部使用標籤,外部無法直接引用;同樣,標籤不能跨函式或跨模組使用。


程式碼範例

範例 1:多層巢狀迴圈的提前終止

// 找到第一個符合條件的 (i, j) 組合後直接離開所有迴圈
search: for (let i = 0; i < 10; i++) {
  for (let j = 0; j < 10; j++) {
    if (i * j > 30) {
      console.log(`找到組合:i=${i}, j=${j}`);
      break search; // 結束外層的 search 迴圈
    }
  }
}
console.log('搜尋結束');

重點break search 讓我們不必在每層迴圈都寫 if 判斷,程式碼更簡潔。

範例 2:continue 標籤跳過特定迭代

// 在外層迴圈的每次迭代,只要內層 j 為奇數,就直接進入下一個外層 i
outerLoop: for (let i = 1; i <= 5; i++) {
  for (let j = 1; j <= 5; j++) {
    if (j % 2 === 1) continue outerLoop; // 偶數才會執行下面的 console.log
    console.log(`i=${i}, j=${j}(偶數)`);
  }
}

說明:使用 continue outerLoop 可以一次性跳過整個內層迴圈的剩餘運算,提升效能。

範例 3:標籤與 switch 的配合

// 依照指令字串決定流程,遇到 "stop" 時直接跳出整個流程
process: {
  const commands = ['play', 'pause', 'stop', 'rewind'];
  for (const cmd of commands) {
    switch (cmd) {
      case 'play':
        console.log('開始播放');
        break;
      case 'pause':
        console.log('暫停');
        break;
      case 'stop':
        console.log('停止指令,離開流程');
        break process; // 離開 process 區塊
      default:
        console.log('未知指令');
    }
  }
  console.log('這行永遠不會被執行');
}

技巧break process 能在 switch 內直接結束外層的程式區塊,避免寫額外的旗標變數。

範例 4:在 try…catch 中使用標籤

transaction: {
  try {
    stepA(); // 可能拋出例外
    stepB();
    stepC();
    console.log('交易全部成功');
  } catch (err) {
    console.warn('交易失敗,原因:', err);
    break transaction; // 立即結束 transaction 區塊
  }
  // 若沒有例外,會執行以下清理工作
  finalize();
}
console.log('程式繼續執行');

觀點:標籤讓例外處理後的流程控制更直觀,避免在 catch 裡寫過多的條件判斷。

範例 5:避免過度使用 – 以旗標變數替代

let found = false;
outer: for (let i = 0; i < 5 && !found; i++) {
  for (let j = 0; j < 5 && !found; j++) {
    if (i === j) {
      found = true;
      console.log(`找到 i=j=${i}`);
      // 若改用 break outer,程式會更簡潔
      // break outer;
    }
  }
}

比較:這個範例示範了 不一定需要標籤,有時使用布林旗標即可達成相同目的。


常見陷阱與最佳實踐

陷阱 說明 建議做法
標籤名稱與變數同名 若標籤與同一作用域內的變數名稱相同,會造成混淆或誤判。 避免使用與變數或函式同名的標籤,可在名稱前加上前綴如 lbl_
過度巢狀 當程式需要多層 break label 時,往往代表設計過於複雜。 重新思考資料結構或使用函式抽離,減少巢狀層級。
for...of/for...in 中使用 continue label 這兩種迭代語法本身已隱含 continue,使用標籤可能產生不易預期的行為。 僅在傳統 for 迴圈或 while 中使用,或先行測試。
標籤跨函式使用 標籤的作用域受限於所在程式區塊,跨函式無效。 將相關程式封裝在同一個區塊或函式內,或改用例外機制。
return 混用 在函式內部使用 break label 之後仍寫 return,可能導致程式碼可讀性下降。 明確註解或將 breakreturn 分開,讓讀者易於追蹤。

最佳實踐

  1. 僅在必要時使用:標籤的主要目的在於「跳脫多層迴圈」。若能以函式、陣列方法(someevery)或旗標變數解決,請優先考慮。
  2. 命名規則:建議使用 lbl_ 前綴或全大寫(如 OUTER_LOOP)以示區別。
  3. 保持簡潔:每個標籤最好只控制一個迴圈或 switch,避免在同一區塊內出現多個相互交錯的標籤。
  4. 加入註解:因標籤語法較少見,務必在 break labelcontinue label 前加上說明,提升團隊可讀性。

實際應用場景

  1. 搜尋與匹配
    在大資料集或多維陣列中搜尋第一筆符合條件的資料時,使用 break label 可立即終止所有迴圈,減少不必要的運算。

  2. 字串或正則表達式的多層驗證
    例如:先檢查字元類型,再檢查長度,最後檢查自訂規則。若任一階段失敗,break label 可直接跳到錯誤處理區塊。

  3. 遊戲開發的回合制邏輯
    在多層迴圈模擬玩家、怪物、效果的回合流程時,某個條件觸發「結束回合」或「直接結束戰鬥」的需求,標籤能讓程式碼寫得更直觀。

  4. 資料庫批次更新
    需要遍歷多筆記錄並執行多個檢查,若發現任意一筆資料不符合規範,立即停止後續更新,避免半完成的狀態。

  5. 複雜的 UI 渲染流程
    在渲染多層嵌套的元件樹時,若某個子元件因錯誤需要 abort 整個渲染流程,可使用 break label 結束外層迴圈或 switch,配合 try…catch 完成清理。


總結

  • 標籤 是 JavaScript 中少見卻強大的控制流程工具,允許我們 精確跳脫 任意層級的迴圈或 switch
  • 使用 break label 可以立即結束外層迴圈,continue label 則能直接進入外層迴圈的下一次迭代,兩者在多層巢狀結構中相當實用。
  • 雖然標籤能簡化某些複雜情境,但 過度依賴 會降低程式可讀性,建議僅在必要且明確的情況下使用,並配合良好的命名與註解。
  • 了解常見陷阱(名稱衝突、過度巢狀、跨作用域使用)以及最佳實踐,可讓你在實務開發中安全、有效地運用標籤。

掌握了標籤語法後,你將能更靈活地控制程式流程,尤其在處理多層迴圈或需要提前終止的業務邏輯時,寫出更乾淨、效能更佳的程式碼。祝你在 JavaScript 的旅程中玩得開心、寫得順手!