Movatterモバイル変換


[0]ホーム

URL:


MDN Web Docs

此頁面由社群從英文翻譯而來。了解更多並加入 MDN Web Docs 社群。

流程控制與例外處理

JavaScript 擁有許多陳述式,特別是流程控制的陳述式,你可以用這些陳述式來增加程式的互動性。這個章節將會概要介紹陳述式。

JavaScript 參考中有比本章更多關於陳述式的細節。 在 Javascript 程式碼中,分號(;)被用來隔開陳述式。

任何 JavaScript 運算式也是一個陳述式。 有關運算式的完整資訊,請參閱運算式與運算子

區塊陳述式

最基本的陳述式是「用於將陳述式分塊」的「區塊陳述式」。程式區塊被以一對大括號隔離開來:

{  陳述式 1;  陳述式 2;  .  .  .  陳述式 n;}

範例

區塊陳述式經常與流程控制陳述式(例如:ifforwhile)搭配使用。

js
while (x < 10) {  x++;}

在這裏,{ x++; } 是區塊陳述式。

重要:JavaScript 在 ECMAScript2015 (第六版)以前的版本並沒有區塊範圍的概念。 在區塊中的變數有效範圍是包含該區塊的函式或者是執行檔,並且在區塊外也可使用它們。換句話說,區塊並不定義了範圍。JavaScript 中的"獨立"區塊將會產生與 C 和 Java 中不同的效果。舉例來說:

js
var x = 1;{  var x = 2;}console.log(x); // 輸出 2

這裏輸出了 2 是因為區塊中變數var x 陳述式擁有與區塊外的var x 相同的有效範圍。在 C 或 Java,相同的程式碼將會輸出 1。

從 ECMAScript2015 版本起, 使用let 定義的變數範圍將被限制於區塊內。

條件陳述式

條件陳述式是一些在指定條件爲真下將被執行的指令。 JavaScript 支援兩種條件陳述式:if...elseswitch

if...else 陳述式

if 陳述式將在「邏輯判斷爲真」下執行接下來的一個陳述式。選擇性的else 陳述式將會在「邏輯判斷爲否」時被執行。if 陳述式的用法看起來如下:

if (指定條件) {  陳述式 1;} else {  陳述式 2;}

指定條件可以是任何會回傳 true 或 false 的運算式。參見Boolean 來進一步瞭解哪些運算式會回傳truefalse。假如指定條件爲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_執行_當_指定條件_爲_否;}

建議不要在以賦值作爲條件運算式,因為"賦值"常常被和"等於"搞混。 例如, 不要寫出如下面的程式碼:

js
if (x = y) {  /* 陳述式 */}

如果你真的需要以賦值作爲條件運算式,一種常見的方式是額外在賦值式外面加上一組括號。例如:

js
if ((x = y)) {  /* 陳述式 */}

爲"否"的值

下列的值會被看作 false(也稱為Falsy 值)

  • false
  • undefined
  • null
  • 0
  • NaN
  • 空字串("")

其他所有的值,包含所有物件,當被作為條件陳述式都會被視為true

不要把"布林真假值"和"布林物件的真假值"弄混了。 例如:

js
var b = new Boolean(false);if (b) // 這會是 Trueif (b == true) // 這會是 false

範例

在下面的範例中,函式checkData 回傳trueText 物件的長度爲三;否則,顯示出 alert 並回傳false

js
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;]}

程序首先尋找一個標籤與運算式的值匹配的case 子句,然後將控制權轉移給該子句,執行與其相關的陳述式。 如果沒有找到匹配的標籤,程序將查找default 子句(選擇性),如果找到,則將控制權轉移到該子句,執行關聯的陳述式。 如果沒有找到default 子句,程序繼續在switch 結束後的陳述式執行。 按照慣例,默認子句是最後一個子句,但並不硬性規定。

與每個case 子句相關聯的break 陳述式(選擇性)確保程序在發現匹配的陳述式之後退出switch,並在switch 後的陳述式中繼續執行。 如果省略break,程序將繼續在switch 陳述式中的下一個陳述式執行。

範例

在下面範例中,如果變數fruittype 為「Bananas」,程序將與「Bananas」匹配並執行相關陳述式。 當遇到break 時,程序離開switch 並執行switch 後的陳述式。 如果省略break,也將執行 case 「Cherries」的陳述式。

js
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;

你可以拋出任何運算式,而不僅僅是特定類型的運算式。以下的程式碼會拋出一些不同類型的例外:

js
throw "Error2"; // 字串形態throw 42; // 數字形態throw true; // True/Falsethrow {  toString: function () {    return "我是物件!";  },};

備註:你可以在拋出例外時指定物件。然後,可以在 catch 區塊中引用對象的屬性。

js
// 創建類型爲 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 區塊在trycatch 區塊執行後執行,但在try...catch 陳述式之後的陳述式之前執行。

以下的範例使用try...catch 陳述式。該範例調用基於傳遞給函數的值並從陣列中檢索月份名稱的函數。如果值不對應於月份數(1-12),則會拋出一個例外,其值為 "InvalidMonthNo",並且catch 區塊中的陳述式將monthName 變數設置為unknown

js
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 區塊。

js
try {  throw "myException"; // 產生例外} catch (e) {  // 用於處理例外的陳述式  logMyErrors(e); // 將例外物件傳給 error handler}

finally 區塊

finally 區塊中包含在trycatch 區塊執行之後但在try...catch 陳述式之後的陳述式之前 執行的陳述式。 無論是否拋出例外,finally 區塊都會執行。 如果拋出例外,則即使沒有catch 區塊處理例外,finally 區塊中的陳述式也會執行。

你可以使用finally 區塊來使腳本在發生例外時正常地結束。例如,你可能需要釋放腳本中綁定的資源。 在以下示例中,打開一個文件,然後執行使用該文件的陳述式(伺服器端 JavaScript 允許你訪問文件)。 如果在打開文件時拋出例外,finally 區塊會在腳本結束之前關閉文件。

js
openMyFile();try {  writeMyFile(theData); // 可能產生例外} catch (e) {  handleError(e); // 處理可能發生的例外} finally {  closeMyFile(); // 總是在 try 結束後關閉檔案}

如果finally 區塊有返回值,那麼該值將成為整個try-catch-finally 過程的返回值,而捨棄trycatch 區塊中的任何返回陳述式:

js
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 區塊還是會被執行):

js
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 構造子。舉例來說:

js
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 有以下幾種狀態:

  • pending:等待中,為初始之狀態,即不是 fulfilled 也不是 rejected。
  • fulfilled:已實現,表示操作成功完成。
  • rejected:已拒絕,表示操作失敗。
  • settled:已完成,表示 Promise 狀態為已實現或已拒絕,但不是等待中。

使用 XHR 載入圖檔

這裏有個簡單的範例,使用了Promise 物件與及XMLHttpRequest 來載入 MDN GitHubpromise-test repository 中的一張圖檔。你也可以觀看結果。 每一步都有註解來讓你慢慢理解 Promise 物件與及 XHR 架構。 下面的版本沒有註解,但藉由觀察Promise 物件的變動你或許可以對 promise 物件有所了解:

js
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 參照頁面,以及使用 Promises 教學。

Help improve MDN

Learn how to contribute.

This page was last modified on byMDN contributors.


[8]ページ先頭

©2009-2025 Movatter.jp