雙10期|基本物件Error及8種錯誤型別

語言: CN / TW / HK

theme: github highlight: a11y-dark


本文已參與「新人創作禮」活動,一起開啟掘金創作之路。

雙10期|基本物件Error及8種錯誤型別

tips:每個技術點都值得優學優寫:10期

好文推薦:

約2萬字-Vue原始碼解讀彙總篇(續更)

前端要會打組合拳,覆盤30+技術點打出的功能

寫在前面

錯誤物件是一種特殊的基本物件。它們擁有基本的 Error 型別,同時也有多種具體的錯誤型別。 認識他們,對於我們合理的處理異常,丟擲異常,可能是有幫助的,對於深入認識 JavaScript 也是有幫助的,錯誤物件(錯誤型別)通常也是程式語言的重要組成部分。

JavaScript 種標準的具體的錯誤型別,主要有 8種:

  • AggregateError(實驗中)
  • EvalError
  • InternalError
  • RangeError
  • ReferenceError
  • SyntaxError
  • TypeError
  • URIError

基本物件 Error

Error 簡述

通過Error的構造器可以建立一個錯誤物件。當執行時錯誤產生時, Error的例項物件會被丟擲。Error物件也可用於使用者自定義的異常的基礎物件。

下面是一個使用 Error 的示例:

js try { throw new Error('遇到了基本錯誤!') } catch (e) { console.error(e.name + ': ' + e.message) // 列印結果:Error: 遇到了基本錯誤! }

Error 的語法是:

// 中括號括起來的都是可選引數, // message:人類可閱讀的關於錯誤的描述 // fileName(非標準):程式碼中導致異常的檔案的檔名 // lineNumber(非標準):程式碼中導致異常的程式碼的行號 new EvalError([message[, fileName[, lineNumber]]])

正是因為一些 js 框架,合理使用了錯誤型別,我們在辨析錯誤的時候才方便了許多, 例如 message:錯誤描述,fileName:發生錯誤的檔名,lineNumber:程式碼中導致異常的程式碼的行號。 這些錯誤資訊的提供,大大方便了定位排查。

下面是一個包含了基本的錯誤資訊的控制檯報錯截圖: image.png

自定義異常型別

如果你想要自定義基於 Error 的異常型別也是被支援的,但需要注意, 在FireFox中丟擲自定義型別的異常可能會顯示不正確的行號和檔名。

下面是一個示例:

```js function MyError (message) { this.name = 'MyError'; this.message = message || 'Default Message'; this.stack = (new Error()).stack; }

MyError.prototype = Object.create(Error.prototype); MyError.prototype.constructor = MyError;

try { throw new MyError(); } catch (e) { console.log(e.name); // 'MyError' console.log(e.message); // 'Default Message' }

try { throw new MyError('custom message'); } catch (e) { console.log(e.name); // 'MyError' console.log(e.message); // 'custom message' } ```

AggregateError

當多個錯誤需要包裝在一個錯誤中時,可以考慮使用 AggregateError。

tips:這是一個實驗中的功能.此功能某些瀏覽器尚在開發中,請參考瀏覽器相容性, 在不同瀏覽器中使用適合的字首。由於該功能對應的標準文件可能被重新修訂, 所以在未來版本的瀏覽器中該功能的語法和行為可能隨之改變。

語法:

// errors 錯誤的描述,預設為空。 // message 錯誤的提示資訊。 new AggregateError(errors[, message])

tips:語法習慣上使用[]把可選內容包裹起來,例如上面,包括那個逗號都是可選的,都被[]包裹了。 這不僅僅是 javascript 這樣做,所以什麼是可選的,通常只要看是否被[]即可, 當然這是在遵守規範或約定的前提下。

下面是一個建立 AggregateError 的示例

js try { throw new AggregateError([ new Error("some error"), ], 'Hello'); } catch (e) { console.log(e instanceof AggregateError); // true console.log(e.message); // "Hello" console.log(e.name); // "AggregateError" console.log(e.errors); // [ Error: "some error" ] }

下面是一個捕獲 AggregateError 的示例

js Promise.any([ Promise.reject(new Error("some error")), ]).catch(e => { console.log(e instanceof AggregateError); // true console.log(e.message); // "All Promises rejected" console.log(e.name); // "AggregateError" console.log(e.errors); // [ Error: "some error" ] });

EvalError

EvalError 表示一個關於 eval 函式的錯誤。 EvalError 不在當前ECMAScript規範中使用, 因此不會被執行時丟擲. 但是物件本身仍然與規範的早期版本向後相容。

語法:

// message:錯誤描述 // fileName:程式碼中導致異常的檔案的檔名 // lineNumber:程式碼中導致異常的程式碼的行號 new EvalError([message[, fileName[, lineNumber]]])

下面是一個建立 EvalError 的示例

js try { throw new EvalError('Hello', 'someFile.js', 10); } catch (e) { console.log(e instanceof EvalError); // true console.log(e.message); // "Hello" console.log(e.name); // "EvalError" console.log(e.fileName); // "someFile.js" console.log(e.lineNumber); // 10 console.log(e.columnNumber); // 0 console.log(e.stack); // "@Scratchpad/2:2:9\n" }

tips:全域性的 EvalError 物件本身不包含任何方法, 然而它通過原型鏈繼承了一些方法。 也支援通過 prototype 向 EvalError 物件中新增自定義屬性。

InternalError

InternalError 物件表示出現在 JavaScript引 擎內部的錯誤。 當 JavaScript 引擎出現內部錯誤時將會丟擲InternalError。 例如: "InternalError: too much recursion"(內部錯誤:遞迴過深)。

tips:需要特別注意的是該特性是非標準的,所以應該謹慎在生產環境中使用它。

語法:

new InternalError([message[, fileName[, lineNumber]]])

一些適用場景:

  • "too many switch cases"(過多case子句);
  • "too many parentheses in regular expression"(正則表示式中括號過多);
  • "array initializer too large"(陣列初始化器過大);
  • "too much recursion"(遞迴過深)。

RangeError

RangeError 物件表示範圍越界錯誤,當一個值不在其所允許的範圍或者集合中,可考慮使用它。

例如,試圖傳遞一個 number 引數給一個範圍內不包含該 number 的函式時則會引發 RangeError。 當傳遞一個不合法的 length 值作為 Array 構造器的引數建立陣列, 或者傳遞錯誤值到數值計算方法(Number.toExponential(), Number.toFixed() ,Number.toPrecision()),會出現 RangeError。

語法:

new RangeError([message[, fileName[, lineNumber]]])

下面是一個使用 RangeError 的示例:

```js let MIN = 3, MAX = 10 let check = function (num) { if (num < MIN || num > MAX) { throw new RangeError('引數必須在這個區間:(' + MIN + ',' + MAX + ')'); } };

try { check(500); } catch (e) { if (e instanceof RangeError) { // 處理越界錯誤 console.error(e.name + ': ' + e.message) } } ```

ReferenceError

ReferenceError 用來表示引用類錯誤,ReferenceError 物件代表當一個不存在的變數被引用時發生的錯誤。 例如,當你嘗試引用一個未被定義的變數時,將會丟擲一個 ReferenceError 。

語法:

new ReferenceError([message[, fileName[, lineNumber]]])

下面是一個建立 ReferenceError 的示例

js try { throw new ReferenceError('引用錯誤', 'that-file.js', 250) } catch (e) { console.log(e instanceof ReferenceError) // true console.log(e.message) // 引用錯誤 console.log(e.name) // "ReferenceError" }

一個捕獲 ReferenceError 的示例

js try { let a = username } catch (e) { console.log(e instanceof ReferenceError) // true console.log(e.message) // username is not defined console.log(e.name) // ReferenceError console.log(e.stack) // ReferenceError: username is not defined at ... }

JavaScript 種有一個“奇怪”的現象,就是“變數提升”,但這種提升又是有區別的, 例如在使用 let 宣告一個變數前就使用它會被丟擲一個 ReferenceError 異常,而使用 var 則不會丟擲 ReferenceError。

下面是一個會丟擲 ReferenceError 的示例。

js console.log(x) // ReferenceError let x = 2

image.png

SyntaxError

SyntaxError 語法錯誤,代表嘗試解析語法上不合法的程式碼的錯誤。 當 Javascript 語言解析程式碼時,Javascript 引擎發現了不符合語法規範的的程式碼時時丟擲 SyntaxError。

語法:

new SyntaxError([message[, fileName[, lineNumber]]])

下面是一個捕獲 SyntaxError 的示例

js try { eval('hoo bar') } catch (e) { console.log(e instanceof SyntaxError) // true console.log(e.message) // Unexpected identifier console.log(e.name) // SyntaxError console.log(e.stack) // SyntaxError: Unexpected identifier at ... }

TypeError

TypeError 表示型別錯誤,表示值的型別不是預期型別時發生的錯誤。 例如,當傳入函式的運算元或引數的型別並非操作符或函式所預期的型別時,將丟擲一個 TypeError 型別錯誤。

語法:

new TypeError([message[, fileName[, lineNumber]]])

下面是一個捕獲 TypeError 的示例

js try { null.f() } catch (e) { console.log(e instanceof TypeError) // true console.log(e.message) // Cannot read properties of null (reading 'f') console.log(e.name) // TypeError console.log(e.stack) // TypeError: Cannot read properties of null (reading 'f') at ... }

下面是一張關於先使用函式表示式,再去宣告會被丟擲 TypeError 的截圖。

image.png

URIError

URIError 物件用來表示,以一種錯誤的方式使用全域性 URI 處理函式,而產生的錯誤。 當向全域性 URI 處理函式傳遞一個不合法的 URI 時,URIError 錯誤會被丟擲。

語法:

new URIError([message[, fileName[, lineNumber]]])

下面是一個使用 URIError 的示例

js try { decodeURIComponent('%@資源地址') } catch (e) { console.log(e instanceof URIError) // true console.log(e.message) // URI malformed(畸形的,難看的) console.log(e.name) // URIError console.log(e.stack) // URIError: URI malformed at decodeURIComponent (<anonymous>) ... }

寫在後面

關於 error 的使用,可能在一些應用的常規頁面開發未必用得上, 但 JavaScript 是高階程式語言,它能做更多的事。就像是在寫 java 介面時處理業務邏輯, 丟擲適當的異常和捕獲異常,可能是比較常見的事。如果 JavaScript 也做那樣的事情, 那麼 Error 相關的知識,結合 throw 語句丟擲一個異常並且用 try...catch 語句捕獲處理它, 就是常見的事了。

即使用得比較少,學習它,對於我們理解 JavaScript 和檢視一些錯誤資訊,排查定位 bug 也是有幫助的。

下面是一些在 vue3原始碼庫 vue-next 種檢索到的錯誤型別的應用的截圖。 我曾寫過 約2萬字-Vue原始碼解讀彙總篇(續更) , 而做這個的目的除了瞭解 vue,就是學習如何設計程式碼。例如本文的主角 Error 應該如何使用,我也會去該庫檢索學習。

image.png

image.png

image.png