JS錯誤處理機制2019-08-19(2)

錯誤處理機制

一、Error實例對象

  • JavaScript 解析或運行時,一旦發生錯誤,引擎就會拋出一個錯誤對象。JavaScript 原生提供Error構造函數,所有拋出的錯誤都是這個構造函數的實例。
  • Error實例對象必須有message屬性,表示出錯時的提示信息。Error實例還提供namestack屬性,分別表示錯誤的名稱和錯誤的堆棧。但它們是非標準的,不是每種實現都有。
    message:錯誤提示信息
    name:錯誤名稱(非標準屬性)
    stack:錯誤的堆棧(非標準屬性)

Error的六個派生對象:

  • SyntaxError 對象(語法錯誤)
    SyntaxError對象是解析代碼時發生的語法錯誤。

  • ReferenceError 對象(引用錯誤)
    ReferenceError對象是引用一個不存在的變量時發生的錯誤。
    例如:將一個值分配給無法分配的對象,比如對函數的運行結果或者this賦值。

  • RangeError 對象(引用錯誤)
    RangeError對象是一個值超出有效范圍時發生的錯誤
    主要有幾種情況,一是數組長度為負數,二是Number對象的方法參數超出范圍,以及函數堆棧超過最大值。

  • TypeError 對象(類型錯誤)
    TypeError對象是變量或參數不是預期類型時發生的錯誤
    例如: 對字符串、布爾值、數值等原始類型的值使用new命令

  • URIError 對象(編碼錯誤)
    URIError對象是URI相關函數的參數不正確時拋出的錯誤

  • EvalError對象(全局錯誤)
    eval函數沒有被正確執行時,會拋出EvalError錯誤。該錯誤類型已經不再使用了,只是為了保證與以前代碼兼容,才繼續保留。

以上這6種派生錯誤,連同原始的Error對象,都是構造函數。開發者可以使用它們,手動生成錯誤對象的實例。這些構造函數都接受一個參數,代表錯誤提示信息(message)。

二、throw 語句
throw語句的作用是手動中斷程序執行,拋出一個錯誤。

if (x <= 0) {
  throw new Error('x 必須為正數');
}
// Uncaught ReferenceError: x is not defined

throw拋出的錯誤就是它的參數,這里是一個Error實例。
throw可以拋出任何類型的值。也就是說,它的參數可以是任何值。

// 拋出一個字符串
throw 'Error!';
// Uncaught Error!

// 拋出一個數值
throw 42;
// Uncaught 42

// 拋出一個布爾值
throw true;
// Uncaught true

// 拋出一個對象
throw {
  toString: function () {
    return 'Error!';
  }
};
// Uncaught {toString: ?}

對于 JavaScript 引擎來說,遇到throw語句,程序就中止了

三、try...catch結構

  • 一旦發生錯誤,程序就中止執行了。JavaScript 提供了try...catch結構,允許對錯誤進行處理,選擇是否往下執行。
  • try語句包含了由一個或者多個語句組成的try塊, 和至少一個catch子句或者一個finally子句的其中一個,或者兩個兼有。
  • 三種形式的try聲明:

1.try...catch

  1. try...finally

  2. try...catch...finally

try {
  throw new Error('出錯了!');
} catch (e) {
  console.log(e.name + ": " + e.message);
  console.log(e.stack);
}
// Error: 出錯了!
//   at <anonymous>:3:9
//   ...
  • catch子句包含try塊中拋出異常時要執行的語句。即:想讓try語句中的內容成功, 如果沒成功,想控制接下來發生的事情,這時可以在catch語句中實現。 如果在try塊中有任何一個語句(或者從try塊中調用的函數)拋出異常控制立即轉向catch子句。如果在try塊中沒有異常拋出,會跳過catch子句
  • catch代碼塊捕獲錯誤之后,程序不會中斷,會按照正常流程繼續執行下去。
  • catch代碼塊之中,還可以再拋出錯誤,甚至使用嵌套try...catch結構。
var n = 100;

try {
  throw n;
} catch (e) {
  if (e <= 50) {
    // ...
  } else {
    throw e;
  }
}
// Uncaught 100
  • catch接受一個參數,表示try代碼塊拋出的值。
  • catch代碼塊之中可以加入判斷語句 if...else。用于判斷錯誤類型,進行不同的處理。
try {
  foo.bar();
} catch (e) {
  if (e instanceof EvalError) {
    console.log(e.name + ": " + e.message);
  } else if (e instanceof RangeError) {
    console.log(e.name + ": " + e.message);
  }
  // ...
}
  • finally子句在try塊和catch之后執行但是在下一個try聲明之前執行。無論是否有異常拋出或捕獲它總是執行

四、finally 代碼塊

  • ry...catch結構允許在最后添加一個finally代碼塊,表示不管是否出現錯誤,都必需在最后運行的語句
function cleansUp() {
  try {
    throw new Error('出錯了……');
    console.log('此行不會執行');
  } finally {
    console.log('完成清理工作');
  }
}

cleansUp()
// 完成清理工作
// Uncaught Error: 出錯了……
//    at cleansUp (<anonymous>:3:11)
//    at <anonymous>:10:1

上面代碼中,由于沒有catch語句塊,一旦發生錯誤,代碼就會中斷執行。中斷執行之前,會先執行finally代碼塊,然后再向用戶提示報錯信息。

function idle(x) {
  try {
    console.log(x);
    return 'result';
  } finally {
    console.log('FINALLY');
  }
}

idle('hello')
// hello
// FINALLY

上面代碼中,try代碼塊沒有發生錯誤,而且里面還包括return語句,但是finally代碼塊依然會執行。而且,這個函數的返回值還是result

  • return語句的執行是排在finally代碼之前,只是等finally代碼執行完畢后才返回。
  • 下面是finally代碼塊用法的典型場景。
openFile();

try {
  writeFile(Data);
} catch(e) {
  handleError(e);
} finally {
  closeFile();
}

上面代碼首先打開一個文件,然后在try代碼塊中寫入文件,如果沒有發生錯誤,則運行finally代碼塊關閉文件;一旦發生錯誤,則先使用catch代碼塊處理錯誤,再使用finally代碼塊關閉文件。

  • try...catch...finally這三者之間的執行順序,例:
function f() {
  try {
    console.log(0);
    throw 'bug';
  } catch(e) {
    console.log(1);
    return true; // 這句原本會延遲到 finally 代碼塊結束再執行
    console.log(2); // 不會運行
  } finally {
    console.log(3);
    return false; // 這句會覆蓋掉前面那句 return
    console.log(4); // 不會運行
  }

  console.log(5); // 不會運行
}

var result = f();
// 0
// 1
// 3

result
// false

上面例子中catch代碼塊結束執行之前,會先執行finally代碼塊。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容