條件判斷

口語上常說的「如果」、「假設」是控制程式運行流程的關鍵語法。

if-else

條件式為 true 時就會執行內容:

const a = 1;
if (a > 0) {
console.log('a 大於 0'); // a > 0 為 true 所以會執行
}

會自動轉型為 true 的是真值 (truthy),false假值 (falsy) 。

以下都會轉為假值:

  • undefined
  • 0
  • ''(空字串)
  • null
  • NaN
if (message) {
console.log('有訊息:', message);
} else {
console.log('沒有訊息'); // 訊息如果是空字串、undefined、null 等
}

因此條件判斷除了大於、小於等數值比較,也經常用在判定某些內容是否存在


switch

需要傳入一個值,然後列舉對應的情境 (case) 與執行內容:

const letter = 'A';
switch (typeof letter) {
case 'string':
console.log('這是字串');
break;
default:
console.log('不是字串');
}
警告

case 中如果沒有 breakreturn,判斷會一直執行下去。

switch 通常用來列舉一個值可能會出現哪些。

下面是一個語意上看起來正確,但實際上有問題的用法

let wallet = 300;
switch (wallet) {
case wallet > 500:
console.log('給我一瓶酒再給我一支菸');
break;
case wallet > 100:
console.log('快把我的悲傷都帶走');
break;
default:
console.log('把愛勇氣希望都賣了能換來多少錢');
}
// 印出 '把愛勇氣希望都賣了能換來多少錢'

所以看起來好像要執行 case wallet > 100 並印出 '快把我的悲傷都帶走',但最後執行了 default 的內容,因為 300 > 100 雖然是對的,但這個條件式回傳的是 true,所以實際上變成 case true:

要執行哪個 case,是看 switch () 括號中的值和 case 的值是否相等,而 switch (300) 並不等於 case true

要進到 wallet > 100 這個 case,只要把 switch(wallet) 改成 switch(true) 即可,
但一般不這麼做是因為不符合語意


三元運算

如果條件判斷只是單純地看某個變數的真假值,並且需要一個回傳值,可以用三元運算簡化程式碼長度:

const result = getData();
// if else 的寫法
if (result) {
console.log('有資料');
} else {
console.log('沒資料');
}
// 三元運算的寫法
console.log(result ? '有資料' : '沒資料');

也可以寫一些程式碼進去執行,如下面範例,但個人覺得三元運算單純用在簡單的取值就好:

const message = getMessage();
// 不好的寫法
message ? console.log('有訊息') : console.log('沒訊息');
// 好一點的寫法
console.log(message ? '有訊息' : '沒訊息');
// 這樣也可以
const message = getMessage() ? '有訊息' : '沒訊息';
console.log(message);

連續條件判斷也可以這樣斷行,但我個人不太會這樣寫:

const letter = 'A';
typeof letter === 'string' ? '這是字串'
: typeof letter === 'number' ? '這是數字'
: typeof letter === 'boolean' ? '這是布林值'
: typeof letter === 'object' ? '這是物件'
: typeof letter === 'undefined' ? '這是 undefined'

短路求值

邏輯運算子 (operator) 會判斷左右兩邊內容的真假值並回傳原始值。每種運算子的真假值判斷方式不同,有可能會提前終止並回傳結果,類似電路的短路概念。

如果原始值本身就是我們需要的內容,就可以使用短路求值來精簡程式碼。

OR

  • 一邊為 true 就成立
  • 返回第一個真值的原始值

例如:getData() 會得到一個陣列或 null,搭配 OR 運算就可以保證 data 最後不會是 null,防止一些意外操作:

// 假設 getData 會回傳陣列或 null
let data = getData() || [];
console.log(data); // 印出原始陣列或是 [],不會有 null

AND

  • 兩邊為 true 才成立,並回傳右邊的值
  • false 會提前返回:
console.log('有東西' && '真的有東西'); // '真的有東西'
console.log(null && '有東西'); // null
console.log(null && undefined); // null

空值合併運算子 (Nullish Coalescing Operator)

  • 左邊是 nullundefined 時回傳右邊的值
console.log(null ?? '有東西'); // '有東西'
console.log('' ?? '這裡也有東西'); // ''

提前排除例外

實作上有時會忘記排除不合法的值,導致後續對著 nullundefined 等等不能操作的資料進行運算,接著產生報錯。

所以通常會在運算前進行一連串的過濾:

function showBodyCondition(bmi) {
// 把不合法的條件移到第一個
if (isNaN(bmi) || typeof bmi !== 'number') {
console.log('請輸入合法的數字');
} else if (bmi < 17.5) {
console.log('過輕');
}
//...
}

early return 也是很常使用的技巧。

函式內只要執行到 return 就會脫離函式,後面的程式碼就不會繼續執行,如下面範例,showPokemonData 一開始就先判斷資料是否還在讀取或者資料不存在:

function showPokemonData(data) {
if (isLoading || !data) {
return;
}
console.log(data);
}

小結

  • if-elseswitch 的使用情境與差異
  • 運用三元運算與短路求值來簡化程式碼
  • 任何資料運算開始前都要檢查,提前排除例外

參考資料