正在翻譯中。
JavaScript擁有許多陳述句,特別是控制流的陳述,你可以用這些陳述來增加你程式的互動性。這個章節將會概要介紹陳述。
JavaScript參考 中有比本章更多關於陳述句的細節. 在Javascript程式碼中,分號(;)被用來隔開陳述句.
任何JavaScript表達式也是一個陳述。 有關表達式的完整信息,請參閱表達式與運算元.
程式區塊陳述
最基本的陳述是"用於將陳述分塊"的"區塊陳述".程式區塊被以一對大括號隔離開來:
{ 陳述1; 陳述2; . . . 陳述n; }
範例
區塊陳述經常被用於控制流陳述(例如:if
, for
, while
).
while (x < 10) { x++; }
在這裏, { x++; }是區塊陳述
.
重要: JavaScript 在 ECMAScript2015 以前的版本並沒有區塊範圍的概念. 在區塊中的變數有效範圍是包含該區塊的函式或者是執行檔,並且在區塊外也可使用它們.換句話說,區塊並不定義了範圍.Javascript中的"獨立"區塊將會產生與C和Java中不同的效果 .舉例來說:
var x = 1; { var x = 2; } console.log(x); // 輸出 2
這裏輸出了2是因為區塊中變數"var x"陳述擁有與區塊外的"var x"相同的有效範圍.在 C o或 Java, 相同的程式碼將會輸出1 .
從 ECMAScript2015 版本起, 使用let定義的變數範圍將被限制於區塊內.
條件陳述句
條件陳述句是一些在指定條件爲真下將被執行的指令. JavaScript支援兩種條件陳述: if...else
和 switch
.
if...else
陳述
if陳述將在"邏輯判斷爲真"下執行接下來的一個陳述
.選擇性的else陳述將會在"邏輯判斷爲否"時被執行. if陳述的用法看起來如下:
if (指定條件) { 陳述句1; } else { 陳述句2; }
指定條件可以是任何會回傳true或false的表達式。參見 布爾值(Boolean) 來進一步瞭解哪些表達式會回傳 true 及 false。假如指定條件爲 true,陳述句 1
會被執行;否則,陳述句2
會被執行。陳述句1
及陳述句 2
可以是任何陳述,包含巢狀 if 陳述。
你也可以藉由 else if 來使用複合的陳述句來測試多種不同的條件,如下:
if (指定條件1) { 陳述句1; } else if (指定條件2) { 陳述句2; } else if (指定條件n) { 陳述句n; } else { 最後陳述句; }
在多個條件中,只有第一個條件爲true的陳述會被執行.若要執行多個陳述,可以將陳述包在同一個程式區塊中({ ... }
) . 通常來說,使用區塊陳述是很好的習慣,尤其在使用巢狀if的時候:
if (指定條件) { 陳述句_1_執行_當_指定條件_爲_真; 陳述句_2_執行_當_指定條件_爲_真; } else { 陳述句_3_執行_當_指定條件_爲_否; 陳述句_4_執行_當_指定條件_爲_否; }
if (x = y) { /* 描述句 */ }
如果你真的需要以賦值作爲條件表達式, 一種常見的方式是額外在賦值式外面加上一組括號. 例如:
if ((x = y)) { /* 描述句 */ }
爲"否"的值
下列的值會被看作false
false
undefined
null
0
NaN
- 空字串 (
""
)
其他所有的值,包含所有物件,當被作為條件陳述句都會被視為True.
不要把"布林真假值"和"布林物件的真假值"弄混了. 例如:
var b = new Boolean(false); if (b) // 這會是True if (b == true) // 這會是false
範例
I在下面的範例中,函式 checkData
回傳 true
當 Text
object 的長度爲三; 否則, 顯示出 alert 並回傳 false
.
function checkData() { if (document.form1.threeChar.value.length == 3) { return true; } else { alert("請輸入恰好三個字元. " + document.form1.threeChar.value + " is not valid."); return false; } }
switch
陳述
switch
陳述允許程式依表達式的不同值來選擇不同標籤. 假如表達式和標籤匹配,程式會執行標籤對應的陳述.範例如下:
switch (表達式) { case 標籤1: 陳述句1 [break;] case 標籤2: 陳述句2 [break;] ... default: 陳述句 [break;] }
程序首先尋找一個標籤與expression的值匹配的case子句,然後將控制權轉移給該子句,執行與其相關的陳述句。 如果沒有找到匹配的標籤,程序將查找default子句(選擇性),如果找到,則將控制權轉移到該子句,執行關聯的陳述句。 如果沒有找到default子句,程序繼續在switch結束後的語句執行。 按照慣例,默認子句是最後一個子句,但並不硬性規定。
與每個case子句相關聯的break陳述句(選擇性)確保程序在發現匹配的陳述句之後退出switch,並在switch後的陳述句中繼續執行。 如果省略break,程序將繼續在switch陳述中的下一個陳述句執行。
範例
在下面範例中,如果變數fruittype為“Bananas”,程序將與“Bananas”匹配並執行相關語句。 當遇到break時,程序離開switch並執行switch後的陳述句。 如果省略break,也將執行case “Cherries”的陳述句。
switch (fruittype) { case "Oranges": console.log("Oranges are $0.59 a pound."); break; case "Apples": console.log("Apples are $0.32 a pound."); break; case "Bananas": console.log("Bananas are $0.48 a pound."); break; case "Cherries": console.log("Cherries are $3.00 a pound."); break; case "Mangoes": console.log("Mangoes are $0.56 a pound."); break; case "Papayas": console.log("Mangoes and papayas are $2.79 a pound."); break; default: console.log("Sorry, we are out of " + fruittype + "."); } console.log("Is there anything else you'd like?");
例外處理陳述
你可以用以 throw
陳述丟出例外,並以 try...catch
陳述處理之.
例外的形態
任何物件(object)都可以在JavaScript中被拋出。 然而,並非所有拋出的物件都相同。 雖然將數字或字串作為錯誤物件使用是相當常見的,但使用為此目的專門創造的一種例外物件類型通常更有效:
throw
陳述
使用throw語句拋出例外。當拋出例外時,你要指定包含在要拋出物件中的值:
throw expression;
您可以拋出任何表達式,而不僅僅是特定類型的表達式。 以下的程式碼會拋出一些不同類型的例外:
throw "Error2"; // 字串形態 throw 42; // 數字形態 throw true; // True/False throw {toString: function() { return "我是物件!"; } };
// 創建類型爲 UserException 的物件 function UserException(message) { this.message = message; this.name = "UserException"; } // 讓例外轉換成整齊的字串當它被當作字串使用時 // (舉例來說:於 error console) UserException.prototype.toString = function() { return this.name + ': "' + this.message + '"'; } // 創建一個物件的實例並丟出它 throw new UserException("Value too high");
try...catch
陳述
try ... catch語句標記了一組要嘗試的陳述句,並在拋出例外時指定一個或多個響應。 如果例外被拋出,try ... catch語句捕獲它。
try ... catch語句包括一個try塊,它包含一個或多個陳述句,零個或多個catch塊,包含在try塊中拋出例外時該做什麼的陳述句。 也就是說,你希望try塊成功,如果它不成功,你希望控制權傳遞給catch塊。 如果try塊內的任何語句(或在try塊內調用的函數中)拋出例外,則控制立即切換到catch塊。 如果在try塊中沒有拋出例外,則跳過catch塊。 finally塊在try和catch塊執行後執行,但在try ... catch陳述句之前的語句之前執行。
以下的範例使用try ... catch陳述句。該範例調用基於傳遞給函數的值並從陣列中檢索月份名稱的函數。如果值不對應於月份數(1-12),則會拋出一個例外,其值為“InvalidMonthNo”,並且catch塊中的陳述句將monthName變數設置為unknown。
function getMonthName(mo) { mo = mo - 1; // Adjust month number for array index (1 = Jan, 12 = Dec) var months = ["Jan","Feb","Mar","Apr","May","Jun","Jul", "Aug","Sep","Oct","Nov","Dec"]; if (months[mo]) { return months[mo]; } else { throw "InvalidMonthNo"; //throw 關鍵字在這裏被使用 } } try { // statements to try monthName = getMonthName(myMonth); // 函式可以丟出例外 } catch (e) { monthName = "unknown"; logMyErrors(e); // 將例外傳至例外處理機制 }
catch
區塊
你可以使用 catch 區塊來處理 try 區塊可能丟出的例外。
catch (catchID) { 陳述句 }
catch塊指定用來保存throw語句所丟出的值的標識符(前面語法中的catchID) 您可以使用此標識符獲取有關被拋出的例外的信息。 JavaScript在進入catch塊時創建此標識符; 標識符僅持續catch塊的持續時間; 在catch塊完成執行後,標識符不再可用。
例如,下列的程式碼中丟出了一個例外,當例外發生後,控制權被轉交給 catch 區塊。
try { throw "myException"; // 產生例外 } catch (e) { // 用於處理例外的陳述句 logMyErrors(e); // 將例外物件傳給error handler }
finally
區塊
finally區塊中包含 在try和catch塊執行之後但在try ... catch陳述之後的語句之前 執行的語句。 無論是否拋出例外,finally區塊都會執行。 如果拋出例外,則即使沒有catch區塊處理例外,finally塊中的陳述句也會執行。
您可以使用finally塊來使腳本在發生例外時正常地結束; 例如,您可能需要釋放腳本中綁定的資源。 在以下示例中,打開一個文件,然後執行使用該文件的陳述句(服務器端JavaScript允許您訪問文件)。 如果在打開文件時拋出例外,finally塊會在腳本結束之前關閉文件。
openMyFile(); try { writeMyFile(theData); //可能產生例外 } catch(e) { handleError(e); //處理可能發生的例外 } finally { closeMyFile(); //總是在try結束後關閉檔案 }
如果finally區塊有返回值,那麼該值將成為整個try-catch-finally過程的返回值,而捨棄try和catch塊中的任何返回語句:
function f() { try { console.log(0); throw "bogus"; } catch(e) { console.log(1); return true; // 這個回傳會被擱置 // 直到 finally 區塊結束 console.log(2); // 不會到達這裏 } finally { console.log(3); return false; // 覆寫先前的 "return" console.log(4); // 不會到達這裏 } // "return false" 在這裏被執行 console.log(5); // 不會到達這裏 } f(); // console 0, 1, 3; 會回傳false
finally區塊覆寫返回值也適用於在catch區塊中拋出或重新拋出的例外(即便在catch中再次丟出例外,catch所屬的finally區塊還是會被執行):
function f() { try { throw "bogus"; } catch(e) { console.log('caught inner "bogus"'); throw e; // 此處的throw陳述將被擱置到 // finally區塊結束 } finally { return false; // 覆寫先前的"throw" } // "return false" 在此被執行 } try { f(); } catch(e) { // 這裏永遠不可能到達因為在f函式中catch的throw // 被finally中的return覆寫了 console.log('caught outer "bogus"'); } // 輸出 -> caught inner "bogus"
巢狀 try...catch 陳述
你可以使用一個或多個的 try...catch
陳述. 假如一個內層的try...catch
陳述不具有 catch
塊, 它將必須要有finally塊與及封閉的 try...catch
陳述來檢測是否有符合的例外.
使用 Error
物件
根據錯誤的類型,您可以使用“name”和“message”屬性來獲取更精確的資訊。 'name'提供了錯誤所屬的類別(class)(例如,'DOMException'或'Error'),而'message'通常提供藉由將錯誤物件轉換為字串所獲得的更簡潔的資訊。參見 巢狀 try 區塊 位於 try...catch
參考資料頁面.
假如您要丟出自定義的例外, 為了方便使用這些屬性(例如,如果你的catch區塊並不要區分你自己的例外和系統的),你可以使用Error構造子。舉例來說:
function doSomethingErrorProne () { if (ourCodeMakesAMistake()) { throw (new Error('The message')); } else { doSomethingToGetAJavascriptError(); } } .... try { doSomethingErrorProne(); } catch (e) { console.log(e.name); // 紀錄 'Error' console.log(e.message); // 紀錄 'The message' 或者其他 JavaScript 例外的資訊) }
Promises容器
從 ECMAScript2015 起, JavaScript 支援 Promise
物件,允許您控制延遲和異步操作的流程。
Promise
有以下幾種狀態:
- 等待: 初始狀態,不是滿足或拒絕.
- 滿足: 操作成功.
- 拒絕: 操作失敗.
- 安定: 以上皆非的一種狀態.
使用XHR載入圖檔
這裏有個簡單的範例,使用了 Promise物件
與及 XMLHttpRequest
來載入 MDN GitHub promise-test repository中的一張圖檔. 你也可以觀看結果. 每一步都有註解來讓您慢慢理解 Promise物件與及XHR架構. 下面的版本沒有註解,但藉由觀察 Promise
物件的變動您或許可以對promise物件有所遼解:
function imgLoad(url) { return new Promise(function(resolve, reject) { var request = new XMLHttpRequest(); request.open('GET', url); request.responseType = 'blob'; request.onload = function() { if (request.status === 200) { resolve(request.response); } else { reject(Error('Image didn\'t load successfully; error code:' + request.statusText)); } }; request.onerror = function() { reject(Error('There was a network error.')); }; request.send(); }); }
以獲得更多資訊,查看 Promise
參照頁面.