1. 程式人生 > >js 系統教程-17-js 語法之異常處理-error,自定義異常,try catch finally

js 系統教程-17-js 語法之異常處理-error,自定義異常,try catch finally

目錄

錯誤處理機制

Error 例項物件

JavaScript 解析或執行時,一旦發生錯誤,引擎就會丟擲一個錯誤物件。JavaScript 原生提供Error建構函式,所有丟擲的錯誤都是這個建構函式的例項。

var err = new Error('出錯了');
err.message // "出錯了"

JavaScript 語言標準只提到,Error例項物件必須有message屬性,表示出錯時的提示資訊,沒有提到其他屬性。大多數 JavaScript 引擎,對Error例項還提供name和stack屬性,分別表示錯誤的名稱和錯誤的堆疊,但它們是非標準的,不是每種實現都有。

  • message:錯誤提示資訊

  • name:錯誤名稱(非標準屬性)

  • stack:錯誤的堆疊(非標準屬性)

原生錯誤型別

Error 例項物件是最一般的錯誤型別,在它的基礎上,JavaScript 還定義了其他6種錯誤物件。也就是說,存在Error的6個派生物件。

SyntaxError 物件

SyntaxError物件是解析程式碼時發生的語法錯誤。

// 變數名錯誤
var 1a;
// Uncaught SyntaxError: Invalid or unexpected token

// 缺少括號
console.log 'hello');
// Uncaught SyntaxError: Unexpected string

上面程式碼的錯誤,都是在語法解析階段就可以發現,所以會丟擲SyntaxError。第一個錯誤提示是“token 非法”,第二個錯誤提示是“字串不符合要求”。

ReferenceError 物件

ReferenceError 物件是引用一個不存在的變數時發生的錯誤。

// 使用一個不存在的變數
unknownVariable
// Uncaught ReferenceError: unknownVariable is not defined
另一種觸發場景是,將一個值分配給無法分配的物件,比如對函式的執行結果或者this賦值。

// 等號左側不是變數
console.log() = 1
// Uncaught ReferenceError: Invalid left-hand side in assignment
// this 物件不能手動賦值 this = 1 // ReferenceError: Invalid left-hand side in assignment

上面程式碼對函式console.log的執行結果和this賦值,結果都引發了ReferenceError錯誤。

RangeError 物件

RangeError 物件是一個值超出有效範圍時發生的錯誤。主要有幾種情況,一是陣列長度為負數,二是Number物件的方法引數超出範圍,以及函式堆疊超過最大值。

// 陣列長度不得為負數
new Array(-1)
// Uncaught RangeError: Invalid array length

TypeError 物件

TypeError 物件是變數或引數不是預期型別時發生的錯誤。比如,對字串、布林值、數值等原始型別的值使用new命令,就會丟擲這種錯誤,因為new命令的引數應該是一個建構函式。

new 123
// Uncaught TypeError: number is not a func

var obj = {};
obj.unknownMethod()
// Uncaught TypeError: obj.unknownMethod is not a function

上面程式碼的第二種情況,呼叫物件不存在的方法,也會丟擲TypeError錯誤,因為obj.unknownMethod的值是undefined,而不是一個函式。

URIError 物件

URIError 物件是 URI 相關函式的引數不正確時丟擲的錯誤,
主要涉及encodeURI()、decodeURI()、encodeURIComponent()、decodeURIComponent()、escape()和unescape()這六個函式。

decodeURI('%2')
// URIError: URI malformed

EvalError 物件

eval函式沒有被正確執行時,會丟擲EvalError錯誤。該錯誤型別已經不再使用了,只是為了保證與以前程式碼相容,才繼續保留。

自定義錯誤

除了 JavaScript 原生提供的七種錯誤物件,還可以定義自己的錯誤物件。

function UserError(message) {
  this.message = message || '預設資訊';
  this.name = 'UserError';
}

UserError.prototype = new Error();
UserError.prototype.constructor = UserError;

上面程式碼自定義一個錯誤物件UserError,讓它繼承Error物件。然後,就可以生成這種自定義型別的錯誤了。

new UserError('這是自定義的錯誤!');

throw 語句

throw語句的作用是手動中斷程式執行,丟擲一個錯誤。

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

上面程式碼中,如果變數x小於0,就手動丟擲一個錯誤,告訴使用者x的值不正確,整個程式就會在這裡中斷執行。
可以看到,throw丟擲的錯誤就是它的引數,這裡是一個Error例項。

throw也可以丟擲自定義錯誤。

function UserError(message) {
  this.message = message || '預設資訊';
  this.name = 'UserError';
}

throw new UserError('出錯了!');
// Uncaught UserError {message: "出錯了!", name: "UserError"}

上面程式碼中,throw丟擲的是一個UserError例項。

實際上,throw可以丟擲任何型別的值。也就是說,它的引數可以是任何值。

// 丟擲一個字串
throw 'Error!';
// Uncaught Error!

// 丟擲一個數值
throw 42;
// Uncaught 42

// 丟擲一個布林值
throw true;
// Uncaught true

// 丟擲一個物件
throw {
  toString: function () {
    return 'Error!';
  }
};
// Uncaught {toString: ƒ}

對於 JavaScript 引擎來說,遇到throw語句,程式就中止了。

引擎會接收到throw丟擲的資訊,可能是一個錯誤例項,也可能是其他型別的值。

try…catch 結構

一旦發生錯誤,程式就中止執行了。JavaScript 提供了try…catch結構,允許對錯誤進行處理,選擇是否往下執行。

try {
  throw new Error('出錯了!');
} catch (e) {
  console.log(e.name + ": " + e.message);
  console.log(e.stack);
}
// Error: 出錯了!
//   at <anonymous>:3:9
//   ...

上面程式碼中,try程式碼塊丟擲錯誤(上例用的是throw語句),JavaScript 引擎就立即把程式碼的執行,轉到catch程式碼塊,或者說錯誤被catch程式碼塊捕獲了。catch接受一個引數,表示try程式碼塊丟擲的值。

如果你不確定某些程式碼是否會報錯,就可以把它們放在try…catch程式碼塊之中,便於進一步對錯誤進行處理。

try {
  f();
} catch(e) {
  // 處理錯誤
}

上面程式碼中,如果函式f執行報錯,就會進行catch程式碼塊,接著對錯誤進行處理。

catch程式碼塊捕獲錯誤之後,程式不會中斷,會按照正常流程繼續執行下去。

try {
  throw "出錯了";
} catch (e) {
  console.log(111);
}
console.log(222);
// 111
// 222

上面程式碼中,try程式碼塊丟擲的錯誤,被catch程式碼塊捕獲後,程式會繼續向下執行。

catch程式碼塊之中,還可以再丟擲錯誤,甚至使用巢狀的try…catch結構。

var n = 100;

try {
  throw n;
} catch (e) {
  if (e <= 50) {
    // ...
  } else {
    throw e;
  }
}
// Uncaught 100

上面程式碼中,catch程式碼之中又丟擲了一個錯誤。

為了捕捉不同型別的錯誤,catch程式碼塊之中可以加入判斷語句。

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);
  }
  // ...
}

上面程式碼中,catch捕獲錯誤之後,會判斷錯誤型別(EvalError還是RangeError),進行不同的處理。

finally 程式碼塊

try…catch結構允許在最後新增一個finally程式碼塊,表示不管是否出現錯誤,都必需在最後執行的語句

function cleansUp() {
  try {
    throw new Error('出錯了……');
    console.log('此行不會執行');
  } finally {
    console.log('完成清理工作');
  }
}

cleansUp()
// 完成清理工作
// Error: 出錯了……

上面程式碼中,由於沒有catch語句塊,所以錯誤沒有捕獲。執行finally程式碼塊以後,程式就中斷在錯誤丟擲的地方。

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

idle('hello')
// hello
// FINALLY
// "result"

原文地址

原文地址

目錄導航

目錄導航