JavaScript 探險方針 004 – 迴圈

0. 前言


在程式設計中,迴圈循環是個關鍵的概念。迴圈使我們能夠有效地處理重複性任務,從而避免冗長和重複的代碼,提升程式的可讀性和維護性。

那接著讓我們詳細介紹不同的框架與使用情境吧。

1. 重點


只有 for 迴圈中能直接定義變數
善用 label 可以防止跳出整個外層迴圈
針對基本變數與複合變數有不同的迴圈方法

2. 內容


2.1. 基本變數迴圈

2.1.1. for 迴圈

For 迴圈算是普遍最常使用的方式,在短短的範圍內便可以定義變數與迴圈條件。

範例 1: 區域變數

以下提供的是最基礎的迴圈打印,而各位可以發現我使用的是 let 變數,定義 i 為 0,當 < 3 時迴圈執行一輪之後 i +=1,而當 i == 3 時則會停止。

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

// 0
// 1
// 2

範例 2: 變數溢出

如果你翻遍網路或 GPT 基本提供的都是定義 var 變數,各位可能疑惑為何我剛要使用 let 變數。那是為了避免變數溢出,以下舉個例子是延時 1 秒觸發,結果卻不會是剛剛的 0, 1, 2 三筆,而是三個 3 的結果。

JavaScript
for (var i = 0; i < 3; i++) {
  setTimeout(function () {
    console.log(i)
  }, 1000);
}

// 3
// 3
// 3

這是因為剛剛迴圈觸發的方法在反應過來後偵測到的全域變數 i,在短暫的 1 秒之內早已到達 3,便統一打印出了 3 的結果。而利用 let 則能夠將變數限制於迴圈方法之中,依序傳入 i=0, i=1, i=2 則不會受影響。

JavaScript
for (let i = 0; i < 3; i++) {
  setTimeout(function () {
    console.log(i)
  }, 1000);
}

// 0
// 1
// 2

2.2. while 與 do-while 迴圈

while 與 do-while 在語法上相當類似,但 while 事先檢查條件,而 do-while 則是先執行。

範例 1: while 與 do-while 差異

以下範例限制在 i<0,也就是第一次執行的時候,此時 while 不會觸發,但 do-while 事先印出 0 的結果。

JavaScript
{
  let i = 0;

  while (i < 0) {
    console.log(i); i++;
  }
}

//

JavaScript
{
  let i = 0;

  do { console.log(i); i++; } while (i < 0)
}

// 0

2.2. 複合變數迴圈

2.2.1. for … in / for … of

針對複合變數,JavaScript 本身貼心的有提供特殊的方法,不用複雜的定義幾層迴圈。

範例 1: for … in 與 for … of 差異

為甚麼在講解變數型態時沒提及到陣列呢?就下方的例子,定義的資料長這樣: [3, 5, 7, marco:”polo”],在 JS 中的陣列是可以跨物件型態的,結構更像物件的型態。並且後續會提到,在 JS 其架構更類似 stack 與 queue 的存在。

從執行結果,可以看到 for … in 取得的是屬性名稱,於是取得陣列順序 0, 1, 2 與 marco 這個 key 值。而 for … of 取得的是屬性的值,但因為沒索引值而沒有 polo,只打印出 3, 5, 7 實際的數值。

JavaScript
let array = [3, 5, 7];
array.macro = "polo";

console.log(array);

// 屬性名字循環
for (let i in array) {
    console.log(i);
}

// 0
// 1
// 2
// marco

// 屬性數值循環
for (let i of array) {
    console.log(i);
}

// 3
// 5
// 7

2.2.2. 陣列 forEach 方法

而除了固定的迴圈表示式,有些物件也有專屬的函式可以使用。

範例 1: 陣列取值

陣列專屬的 forEach 方法也是用來取數值的方式,並可透過內部 function 的方式進行操作。

JavaScript
{
    let array = [3, 5, 7];
    array.macro = "polo";

    console.log(array);

    array.forEach((element) => { console.log(element); })
}

// 3
// 5
// 7

2.3. 迴圈跳脫

2.3.1. 跳過執行 — continue
範例 1: 跳過 i === 1

當迴圈執行到 i === 1 時,透過 continue 會跳過該任務,並接著後面的工作。適合例外判斷。

JavaScript
for (let i = 0; i < 3; i++) {
    if (i === 1) { continue; } else { console.log(i); }
}

// 0
// 2

2.3.2. 脫出迴圈 — break
範例 1: 在 i === 1 脫出

相較之下,break 則會粗暴的脫出最上層的迴圈,直接中斷後續迴圈工作。適合找到解答就離開。

JavaScript
for (let i = 0; i < 3; i++) {
    if (i === 1) { break; } else { console.log(i); }
}

// 0

2.4. 標籤迴圈

2.4.1. 跳脫到指定迴圈 — break {LABEL}

在很多時候,我們不希望一次跳脫最外層的迴圈,因此後來發明了 label 的定義方式。

範例 1: 內外迴圈

在下面的範例中,我們將外層的 while 標前為 outer,而在第 15 行可以看見,當內迴圈到達 3 時,會脫出到外迴圈接續下一份內迴圈。因此有三個階段的結果。

JavaScript
{
  var x = 0; var y = 0;

  // Outer Loop
  outer: while (true) {
    console.log("Outer loops: " + x);
    x += 1;
    y = 1;
    // Inner Loop
    while (true) {
      console.log("Inner loops: " + y);
      y += 1;
      if (y === 3 && x === 3) {
        // 直達指定迴圈
        break outer;
      } else if (y === 3) {
        // 拖出所有迴圈
        break;
      }
    }
  }
  
// Outer loops: 0
// Inner loops: 1
// Inner loops: 2
//
// Outer loops: 1
// Inner loops: 1
// Inner loops: 2
//
// Outer loops: 2
// Inner loops: 1
// Inner loops: 2

3. 後話


理解並掌握各種迴圈結構對於編寫清晰的程式至關重要。

那基本功都差不多了,接著我們就要開始進到常用的 Array 方法,並開始透過簡易的範例來做示範。

4. 參考


[1] Loops and Iteration — MDN Web Docs
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.