前言

學習如何在程式碼中建立和控制資料流程,進而處理不同的狀況。

圖片來源

 


 

條件判斷並執行決策

程式碼中存在許多狀況需要進行條件判斷,以決定下一步該執行哪一個程式區段,流程圖可以幫助規劃這些情境狀態。

在流程圖中,菱形的狀態代表一個條件判斷點,在此處需要進行條件判斷,並執行決策,此時程式碼便可採取不同路徑流程。

 


 

評估條件與條件敘述句

執行決策時,會包含兩個元件:

  1. 評估條件:對運算式進行評估,並回傳一個結果值。
  2. 條件敘述句:需描述在該情況下應該執行的工作,是基於 if / then / else 的概念。
if (score > 50) {
    document.write('You passed!');
} else {
    document.write('Try again...');
}

以上述程式碼的意思,如果條件判斷為 true ,執行第一組大括號裡的條件敘述句,反之執行第二組,之後也會學到透過兩個( 或以上 )的比較運算子,將多個條件結合。

 


 

比較運算子:評估條件

可以將程式碼中的值與你的預期值比較評估,評估後的結果會以布林值表示: true 或 false 。

比較運算子 名稱 說明 範例
== 等於 比較兩個值( 數字、字串或布林值 )確認它們是否相同。 'Hello' == 'Goodbye'
// false
!= 不等於 比較兩個值( 數字、字串或布林值 )確認它們是否不相同。 'Hello' != 'Goodbye'
// true
=== 嚴格等於 比較兩個值,以確認資料型別和值均相同。 '3' === 3
// false
!== 嚴格不等於 比較兩個值,以確認資料型別和值均不相同。 '3' !== 3
// true
> 大於 檢視左邊的數字是否大於右邊的。 4 > 3
// true
< 大於 檢視左邊的數字是否小於右邊的。 4 < 3
// false
>= 大於等於 檢視左邊的數字是否大於或等於右邊的。 4 >= 3
// true
<= 大於等於 檢視左邊的數字是否小於或等於右邊的。 4 <= 3
// false

 


 

比較運算子組成結構

在任何一種條件下,比較運算子的結構通常會是一個運算子和兩個運算元,運算元會在運算子的兩側,它們可以是值或變數,然後通常運算式前後會以括號標示。

  1. 比較運算子。
  2. 運算元。
  3. 括號標示。

( 運算元不一定要是單一值或是變數名稱,也可以是一個運算式 )

 


 

邏輯運算子

比較運算子通常回傳 true 或 false 的單一結果值,邏輯運算子則可讓你針對多個比較運算子產生的結果值,再進行邏輯判斷,而邏輯運算子是由左至右執行評估,所以如果第一個條件可以提供足夠的資訊來取得答案,那麼就不需要再評估第二個條件了。

邏輯運算子 名稱 說明 範例
&& AND 測試多個條件是否成立。
-
true && true 為 true
true && false 為 false
false && true 為 false
false && false 為 false
((2 < 5) && (3 >= 2))
// true
|| OR 測試至少一個條件。
-
true || true 為 true
true || false 為 true
false || true 為 true
false || false 為 false
((2 < 5) || (2 < 1))
// true
! NOT 將一個布林值轉換成相反值。
-
!true 為 false
!false 為 true
!(2 < 1)
// true

 


 

if 條件判斷式

if 條件判斷式會評估( 或檢測 )一個條件,如果這個條件經評估後為 true ,則位於對應程式碼區塊裡的敘述句均會被執行。

if (score >= 50) {
    congratulate();
}

如上面的範例,如果條件評估為 true ,便會執行大括號裡的 congratulate(); 程式碼,反之則不會。

 


 

if...else 條件判斷式

if...else 條件判斷式會檢測一個條件,如果評估後為 true ,則執行第一個程式碼區塊,反之執行第二個程式碼區塊。

if (score >= 50) {
    // 當評估值為true時執行
    congratulate();
}
else {
    // 當評估值為false時執行
    encourage();
}

 


 

switch 條件判斷式

switch 條件判斷式是由一個稱為 switch 值的變數展開,每個案例均對應一個可能發生的變數值,及應執行的程式碼區塊。

switch (level) {
    case 'One':
        title = 'Level 1';
        break;
    case 'Two':
        title = 'Level 2';
        break;
    default:
        title = 'Test';
        break;
}

如上面的範例,名稱為 level 的變數就是 switch 值,如果這個 level 變數的值是一個字串 One ,那麼第一個案例的程式碼將被執行;如果是字串 Two ,那麼第二個案例將被執行,如果以上兩種都不是,則執行 default 的程式碼。

整個條件判斷會置於一個大括號裡,其中冒號可將案例條件與該案例對應的程式碼分隔,每個案例最後會以 break 關鍵字結束,它告訴 JavaScript 解譯器 switch 條件判斷句已經結束,並繼續執行後續的程式碼。

 

if...else vs. switch

if...else

  • 可以只使用 if 條件判斷句,並不一定需要提供 else 選項。
  • 在一連串的 if 條件判斷句中,即使已找到符合的條件,解譯器還是會檢視全部的條件,因此執行效率會比 switch 敘述句差。

switch

  • 如果沒有符合的案例條件,將會執行預設選項。
  • 如果有符合的案例條件,便會執行對應的程式碼區塊,接著 break 敘述會停止執行 switch 條件判斷敘述裡其他的指令,相較於多個 if 條件判斷敘述,可提供更好的效能。

 


 

型別轉換與弱型別

若你使用 JavaScript 無法理解的資料型別,它會試著將運算合理化,而非直接回報錯誤。

JavaScript 可以在背景將資料型別轉換,以完成一個運算,這個稱之為型別轉換( type coercion ),舉例來說:字串 '1' 在下列運算式中會被轉換為數值 1:('1'>0) ,因此會被評估為 true 。型別轉換會導致程式碼裡有無法預期的值( 也會引起錯誤 ),所以如果要檢查兩個值是否相等,一般認為使用 === 跟 !== 嚴格運算子更適合。

JavaScript 使用的是弱型別( weak typing ),這表示值的資料型別是可以改變的,有些程式語言會要求為每個變數定義資料型別,這就是所謂的強型別( strong typing )。

資料型別 目的
string 文字。
number 數值。
Boolean true 或 false 。
null 空白值。
underfined 已宣告變數,但尚未指定值。

NaN 會被視為數值,當預期的是數值,但並未回傳數值時,可能就會看到 NaN ,例如: ('ten'/2) 。

 


 

真與假值

因為型別轉換,每一個在 JavaScript 裡的值都可以被視為真( truthy )或假( falsy )值。

假( falsy )值會被視為 false ,下方標格表示顯示附有一系列不同內容值的 highScore 變數,它們全都是假值,而假值也可以被視為數值 0 。

說明
var highScore = false; 傳統布林值 false 。
var highScore = 0; 數字 0 。
var highScore = ''; 空白值。
var highScore = 10/'score'; NaN ( 不是一個數字 )。
var highScore; 一個未被指定值的變數。

真( truthy )值會被視為 true ,幾乎所有沒有放在假值表格中的值,都可以視為是 true ,然後真值也可以被視為數值 1 ,除此之外,物件跟陣列也通常被視為真值,這樣的特質常可使用來檢視頁面上的元件是否存在。

說明
var highScore = true; 傳統布林值 true 。
var highScore = 1; 除了 0 之外的數字。
var highScore = 'carrot'; 有內容的字串。
var highScore = 10/5; 數字計算。
var highScore = 'true'; 'true' 字串。
var highScore = '0'; '0' 字串。
var highScore = 'false'; 'false' 字串。

 


 

檢測相等性與存在性

因為一個物件和陣列的存在可以被視為真值,這通常可用於檢測元件是否存在於此頁面中。

if (document.getElementByID('header')) {
    // 元件存在的話執行
} else {
    // 元件不存在的話執行
}

一個一元( unary )運算子表示只需要一個運算元便可以進行運算,並回傳結果值,在上面程式碼中可以看到,一個 if 條件判斷句正檢測頁面中是否有指定的元件存在。

JavaScript 初學者經常會認為以下敘述也有相同效果
if (document.getElementByID('header') == true)
但是這個會回傳一個物件,物件會被視為真值,但並不等同於布林值的 true 。

因為型別轉換, === 和 !== 嚴格運算子比 == 和 != 運算子相較起來,會發生無法預期的值的機率更少。

運算式 結果
(false == 0) true
(false === 0) false
(false == '') true
(false === '') false
(0 == '') true
(0 === '') false
(undefined == null) true
(null == false) false
(undefined == false) false
(null == 0) false
(undefined == 0) false
(undefined === null) false
(NaN == null) false
(NaN == NaN) false

雖然 NaN 會被視為假值,它與任何值都不相等,甚至連它自己都不相等( 因為 NaN 是個未定義的數值,兩個未定義的數值無法相等 )。

 


 

捷徑值

邏輯運算子是由左到右的運算過程,一旦它們取得結果值後,便會採取捷徑方式運算( 也就是停止運算 ),但是它們會回傳讓運算停止的結果值( 不一定是 true 或 false )。

valueA = 0;
valueB = 1;
valueC = 2;

if (valueA || valueB || valueC) {
    // 此技巧可以用於檢測頁面上的元件是否存在
}

上方範例當程式碼在邏輯運算子中遇到 valueB 變數時,它將會採用捷徑方式運算,因為數值 1 會被視為真值,只要在邏輯運算中發現真值,其餘的選項將不會被檢測,因此有經驗的程式設計師通常會:

  • 在 or 運算時,把最有可能回傳真值的程式碼置於最前方;而在 and 運算時,將最有可能回傳假值的程式碼置於最前方。
  • 將需花費最多運算能量的選項置於最後方,如此只要有其他回傳值為真值,該選項就不需要被執行。

 


 

迴圈

迴圈( loops )會檢測條件,如果回傳為 true ,便會運行程式碼區塊,接著條件將被再度檢測,如果它的回傳值仍為 true ,程式碼區塊將再度運行,它會重複檢測直到條件為 false ,以下是三種常見的迴圈類型:

迴圈類型 說明
for 如果你需要指定運行程式碼的次數,就必須要使用 for 迴圈,通常以計數器作為條件,以決定迴圈要運行的次數。
while 當你並不知道程式碼必須運行的次數時,就可以使用 while 迴圈,在這種狀況下,條件不具有計數器的功能,但只要條件的回傳值為 true ,迴圈便會持續運行。
do while do...while 迴圈和 while 迴圈非常類似,最主要的不同在於它會運行大括號裡的程式敘述句至少一次,即使條件評估為 false 。

 


 

迴圈計數器

for 迴圈使用計數器為條件,這樣可以指引程式碼運行特定的次數,而條件是由三個描述句組成的:

初始化

建立一個變數並設定為 0 ,這個變數通常命名為 i ( 有些會命名 index ),並將它用於計數器的功能。

var i = 0;

有時會看到變數被宣告於條件前,如下範例,看每個程式設計師的撰寫習慣:

var i;
for (i = 0; i < 10; i++) {
}

 

條件

迴圈持續執行,直到計數器達到指定次數。

i < 10;
// i的初始值設定為0,所以此範例中,迴圈將運行十次後停止

條件也可能使用變數,如果有個名為 rounds 的變數,此變數保存著測驗的次數,且每次迴圈運行一次就執行一次測驗,那麼條件將會如下:

var rounds = 3;
i < (rounds);

 

更新

每次迴圈執行完大括號裡的敘述句時,若要於計數器上增加一次計數,可使用遞增運算子( ++ );反之則用遞減運算子( -- )。

i++
// 擷取變數i,並使用++運算子將變數i增加1

 


 

循環執行

迴圈會按照下面的順序執行:

for (var i = 0; i < 10; i++) {
    document.write(i);
}
  1. 第一次迴圈執行時,變數 i ( 計數器 )被指定為數值 0 。
  2. 每次迴圈執行時,均檢測條件是否符合,變數 i 是否小於 10 。
  3. 若符合條件,接著便會執行迴圈裡的程式碼( 大括號裡的敘述句 )。
  4. 當程式敘述句執行完畢後,變數 i 會加一。
  5. 當條件不再為 true 時,迴圈將會停止,程式碼會移動到迴圈外的下一行。

 


 

迴圈重要概念

以下三個要點是使用迴圈時需要注意的:

關鍵字

迴圈中會很常看到這兩個關鍵字 break 會終止迴圈執行,並告訴解譯器移動到迴圈外的下一個敘述句程式碼;而 continue 則告訴解譯器繼續目前的迴圈,並再度檢測條件( 如果條件為 true 便再次運行程式碼 )。

迴圈與陣列

如果想要對陣列裡的每個項目套用相同的程式碼,迴圈對於陣列的資料處理是非常有效的。

效能議題

當瀏覽器遇到 JavaScript 時,它會執行所有正在進行的工作,直到它將程式碼執行完畢,正是如此,如果迴圈包含許多資料項目就會導致頁面下載速度變慢,然後如果條件永遠不回傳 false 值,這會成為一個無限迴圈,程式碼將不會停止運行直到你的瀏覽器記憶體不足為止。

 


 

運用 for 迴圈

for 迴圈有宣告索引變數,也因為宣告了索引變數,所以可以記錄目前跑了幾次迴圈,迴圈次數到了就可以跳出迴圈了。

for (初始值; 條件; 結束時的變動) {
    // 你想重複執行的動作
}

 


 

運用 while 迴圈

while 迴圈不須宣告索引變數,只要執行條件仍然滿足,就可以一直迴圈下去。

while (執行條件) {
    重複執行的程式們
}

但其實 while 迴圈也可達成 for 迴圈的任務,只要自行在「 迴圈外 」宣告索引變數,並在「 迴圈內 」寫入每次迭代時索引變數的變化,就可達到同樣的效果,如下:

let i = 1
while (i <= 10) {
    重複執行的程式們
    i++
}

 


 

for 跟 while 迴圈差在哪?

當迭代次數已知,也就是當你知道要跑幾次迴圈時,可使用 for 迴圈;而當只知道迴圈執行條件,還不清楚總共需跑幾次迴圈時,就只能使用 while 迴圈。

兩種寫法主要的差異在於:

  1. 索引變數的有效範圍: for 迴圈的索引變數只在迴圈內有效,而 while 的則在圈外也有效。
  2. 索引變數變化的位置: for 迴圈一律在進入迴圈前;而 while 則可任意選擇其在迴圈內的位置。

 


 

運用 do while 迴圈

while 和 do while 的語法非常像, while 是會檢查條件是否成立,成立才執行下面的指令,而 do while 則是先執行那些指令,再去檢查條件是否成立,所以至少會先執行一次。

do {
    執行動作
} while (條件);

下面範例的 do while 迴圈將會印出 1 次 test ,由此可見此迴圈至少一定會執行 1 次。

int y = 1;
do {
    Response.write("test");
    y++;
} while(y < 1);

下面範例的 while 迴圈將不會印出任何文字。

int y = 1;
while (y < 1) {
    Response.write("test");
    y++;
}

 


 

參考資料

  1. JavaScript & jQuery 網站互動設計程式進化之道( Jon Duckett 著、謝銘倫 譯 )
  2. 神之迴圈: 何時用While? 何時用For?
  3. JavaScript基本功修練:Day10 - for、for與while的差別、do while、break、continue
  4. 網頁設計及程式設計教學:while 與 do-while 迴圈

#js #javascript #JS註冊組 #JavaScript & JQuery #網站互動設計程式進化之道 #if #else #比較運算子 #邏輯運算子 #if...else #switch #迴圈 #loops #for #while #do...while #break #continue







Related Posts

踏出轉職的第一步

踏出轉職的第一步

[Week7] - Web Storage 物件:LocalStorage / SessionStorge

[Week7] - Web Storage 物件:LocalStorage / SessionStorge

<form> Attributes

<form> Attributes


Comments