Minghsin University of Science and Technology
Uedu Main Site
Explore Uedu
Student Console
Register as Member/Login
Research Informed Consent Center
Survey Center
Educational Big Data Challenge
Claim or create a course
Try a Scenario Task
Support & Messages
Uptime Data

UeduGPTs

--

Jupyters

1

Local AI

--

Uedu Code

--

明新科大 AQI 70 24°C PM2.5 19
AI Reply Desktop Notifications

Show a desktop notification when the AI TA finishes replying

Chat Message Notifications

Notify me when classmates post messages in the forum

Sound notification

Play an alert sound whenever there is a new notification

Unit 07

流程控制

if、switch、for、while、break 與 continue
Interaction實作 20 minute(s)

Learning Objectives

  • 用 if、else if、else 依條件選擇要執行的程式,並判斷哪些值會被當成 false
  • 用 switch 依一個值選擇 case,說明 break 的作用與忘了 break 時的穿透
  • 用三元運算子寫出簡短的二選一
  • 用 for、while、do…while 重複執行程式,並說明三者的差別
  • 用 break、continue 與 label 控制迴圈提早結束或跳過一圈

為什麼需要流程控制

到目前為止,程式都是由上往下一行一行執行。真正的程式常常需要:

  • 選擇:分數 90 分以上顯示 A,其他顯示 B;使用者沒登入就顯示登入按鈕
  • 重複:把 50 位同學的成績一一加總;每秒更新一次時鐘

這兩件事分別由選擇敘述(if、switch)與迴圈(for、while、do…while)負責。 它們都會搭配區塊(block)使用:一對大括號 { } 把好幾個敘述包成一組,條件成立時整組一起執行。

if (條件) {
  敘述 1;
  敘述 2;
}

區塊裡只有一個敘述時,大括號可以省略,但很容易在之後加一行時出錯,建議一律寫上大括號。

if…else if…else:第一個成立的條件才執行

grade 被呼叫兩次。第一次 score 是 85:注意第 4 行的條件不成立,直接跳到第 6 行檢查下一個條件;第 6 行成立之後,後面的 else if、else 都不再檢查。

條件不一定是 true 或 false

if (…) 的括號裡可以放任何值,JavaScript 會先把它轉成布林值。只有下面六種值會被當成 false,叫做 falsy:

值 說明
false 布林值 false 本身
0 數字 0(-0 也是)
'' 空字串
null 空值
undefined 未定義
NaN 不是數字

其他的值都是 truthy,包括 '0'、'false'(不是空字串)、[](空陣列)、{}(空物件)。 所以 if (name) 常用來檢查「有沒有填名字」:空字串會被當成 false。

三元運算子(條件 ? 成立時的值 : 不成立時的值)是 if…else 的簡短寫法,適合「二選一得到一個值」的情況:

const result = score >= 60 ? '及格' : '不及格';

邏輯比較複雜時還是用 if…else,三元運算子一層一層套下去會很難讀。

哪些值是 falsy

用三元運算子檢查陣列裡的八個值。先猜猜看:'0'、[] 和 'false' 會被當成 true 還是 false?

switch:依一個值選擇 case

當你要拿同一個值和好幾個可能的值比較時,用 switch 比一長串 else if 清楚:

switch (運算式) {
  case 值1:
    // 運算式 === 值1 時執行
    break;
  case 值2:
    // 運算式 === 值2 時執行
    break;
  default:
    // 都不符合時執行(可以省略)
}

三個規則:

  • 比對用的是嚴格相等 ===:switch ('1') 不會進入 case 1:
  • 找到符合的 case 後,會一直往下執行,直到遇到 break 或 switch 結束。忘了寫 break 時,後面的 case 也會執行,這叫穿透(fall-through)
  • 都不符合時執行 default

穿透有時是刻意的:幾個 case 要做同一件事時,可以把 case 疊在一起。

switch (month) {
  case 12:
  case 1:
  case 2:
    season = '冬天';
    break;
  // …
}

switch、break 與穿透

第一個 switch 每個 case 都有 break。第二個 switch 的 case 2 沒有 break:看第 22 行執行完之後,程式往哪一行走?

想一想:選擇敘述

1.

下面的程式會印出什麼?

const input = '0';
if (input) {
  console.log('有輸入');
} else {
  console.log('沒有輸入');
}
2.

下面的程式會印出什麼?

const level = 1;
switch (level) {
  case 1:
    console.log('初級');
  case 2:
    console.log('中級');
    break;
  case 3:
    console.log('高級');
}
3.

下面的程式會印出什麼?

const choice = '2';
switch (choice) {
  case 2:
    console.log('選了二');
    break;
  default:
    console.log('不認得');
}
第 1 次作答

三種迴圈

迴圈 寫法 適合
for for (初始; 條件; 遞增) { … } 知道要跑幾圈,例如 1 到 10、走訪陣列的索引
while while (條件) { … } 不知道要跑幾圈,只知道什麼時候該停
do…while do { … } while (條件); 至少要先執行一次,再決定要不要繼續

for 的執行順序:

  1. 執行初始(只有一次),例如 let i = 1
  2. 檢查條件,成立就執行本體;不成立就結束迴圈
  3. 本體執行完,執行遞增(例如 i++),回到第 2 步

用 let 宣告的迴圈變數只活在迴圈裡,迴圈結束後就不見了。

要依序拿出陣列的每一個元素時,for…of 更簡潔,不需要自己管索引:

for (const color of ['red', 'green', 'blue']) {
  console.log(color);
}

物件要用 for…in,兩者的差別在下一課〈物件〉說明。

寫迴圈時一定要確認條件總有一天會不成立,否則就是停不下來的無窮迴圈,網頁會卡住。

for 迴圈:1 加到 5

看第 3 行出現了好幾次:每一次都是「遞增之後再檢查條件」。注意 i 變成 6 的那一步,條件不成立,迴圈結束,第 6 行時 i 已經從變數區消失了。

while 與 do…while 的差別

前兩個迴圈的條件一開始就不成立(10 < 3 是 false)。while 一次都不執行,do…while 先執行了一次。第三個迴圈事先不知道要跑幾圈,只知道「超過 100 就停」,所以用 while。

break 與 continue

敘述 作用
break 立刻結束整個迴圈(或 switch),跳到迴圈後面的程式
continue 跳過這一圈剩下的部分,直接進入下一圈:for 會先執行遞增,while 會回去檢查條件

巢狀迴圈裡,break 和 continue 只影響最內層的迴圈。要一次跳出外層,可以替外層迴圈加上 label(標籤), 再寫 break 標籤名稱:

outer:
for (…) {
  for (…) {
    if (找到了) break outer;   // 兩層一起結束
  }
}

label 在實際的程式裡不常用;多數時候把巢狀迴圈放進函式,找到時直接 return,會更容易讀。

continue 跳過一圈,break 結束迴圈

3 和 6 是 3 的倍數,遇到 continue 跳過不印;i 變成 8 時遇到 break,迴圈直接結束,9 和 10 都不會執行到。

巢狀迴圈與 label

上半段是小型乘法表:外層 i 每跑一圈,內層 j 都從 1 跑到 3。下半段找乘積為 4 的組合,找到時用 break outer 一次跳出兩層迴圈。

想一想:迴圈

1.

下面的程式會印出什麼?

const out = [];
for (let i = 1; i <= 5; i++) {
  if (i === 2) continue;
  if (i === 4) break;
  out.push(i);
}
console.log(out.join(','));
2.

下面的程式會印出什麼?

let count = 0;
do {
  count++;
} while (count > 5);
console.log(count);
3.

下面的程式會印出什麼?

for (let i = 0; i < 3; i++) {
  for (let j = 0; j < 3; j++) {
    if (j === 1) break;
    console.log(i, j);
  }
}
第 1 次作答

實作:FizzBuzz

用 for 迴圈印出 1 到 15,但是:3 的倍數印 Fizz、5 的倍數印 Buzz、同時是 3 和 5 的倍數印 FizzBuzz,其他數字照常印出。想一想:if…else if 的順序要怎麼排?

你的輸出
預期輸出

重點精華回顧

  • if…else if…else 由上往下檢查,第一個成立的條件才執行,後面的都跳過。
  • false、0、''、null、undefined、NaN 是 falsy,其他值(包括 '0'、[])都是 truthy。
  • 三元運算子 條件 ? A : B 適合簡短的二選一。
  • switch 用 === 比對 case,執行到 break 才離開;忘了 break 會穿透到下一個 case;都不符合時執行 default。
  • for 適合知道圈數的重複;while 先檢查再執行,條件成立就一直重複;do…while 至少執行一次。
  • break 結束整個迴圈,continue 跳過這一圈;巢狀迴圈要一次跳出外層時可以用 label。
這一課完成了!
Next lesson:物件
你目前沒有登入,學習進度只存在這個瀏覽器。 Login 後,進度會跟著帳號,換電腦也看得到。