簡體   English   中英

檢查 JS 中的 typeof 錯誤

[英]checking for typeof error in JS

在 JS 中,似乎無法檢查傳遞給 function 的參數實際上是“錯誤”類型還是錯誤實例。

例如,這是無效的:

typeof err === 'error'

因為只有 6 種可能的類型(以字符串的形式):

typeof 運算符將類型信息作為字符串返回。 typeof返回六個可能的值:

“數字”、“字符串”、“布爾”、“對象”、“函數”和“未定義”。

MSDN

但是,如果我有一個像這樣的簡單用例怎么辦:

function errorHandler(err) {

    if (typeof err === 'error') {
        throw err;
    }
    else {
        console.error('Unexpectedly, no error was passed to error handler. But here is the message:',err);
    }
}

那么確定參數是否是錯誤實例的最佳方法是什么?

instanceof運算符有什么幫助嗎?

您可以使用instanceof運算符(但請參閱下面的警告!)。

var myError = new Error('foo');
myError instanceof Error // true
var myString = "Whatever";
myString instanceof Error // false

如果錯誤是在與檢查發生位置不同的窗口/框架/iframe 中引發的,則上述方法將不起作用。 在這種情況下, instanceof Error檢查將返回 false,即使對於Error對象也是如此。 在這種情況下,最簡單的方法是鴨子類型。

if (myError && myError.stack && myError.message) {
  // it's an error, probably
}

但是,如果您有包含stackmessage屬性的非錯誤對象,則鴨子類型可能會產生誤報。

我問了最初的問題——@Trott 的回答肯定是最好的。

然而,由於 JS 是一種動態語言,並且有如此多的 JS 運行時環境, instanceof運算符可能會失敗,尤其是在前端開發中跨越 iframe 等邊界時。 參見: https : //github.com/mrdoob/three.js/issues/5886

如果你對鴨子打字沒問題,這應該很好:

let isError = function(e){
 return e && e.stack && e.message;
}

我個人更喜歡靜態類型語言,但如果您使用的是動態語言,最好就其本身而言采用動態語言,而不是強迫它表現得像靜態類型語言。

如果你想更精確一點,你可以這樣做:

   let isError = function(e){
     return e && e.stack && e.message && typeof e.stack === 'string' 
            && typeof e.message === 'string';
    }
var myError = new Error('foo');
myError instanceof Error // true
var myString = "Whatever";
myString instanceof Error // false

唯一的問題是

myError instanceof Object // true

另一種方法是使用構造函數屬性。

myError.constructor === Object // false
myError.constructor === String // false
myError.constructor === Boolean // false
myError.constructor === Symbol // false
myError.constructor === Function // false
myError.constructor === Error // true

雖然需要注意的是,這個匹配是非常具體的,例如:

myError.constructor === TypeError // false

您可以使用Object.prototype.toString輕松檢查對象是否為Error ,這也適用於不同的幀。

function isError(obj){
    return Object.prototype.toString.call(obj) === "[object Error]";
}

 function isError(obj){ return Object.prototype.toString.call(obj) === "[object Error]"; } console.log("Error:", isError(new Error)); console.log("RangeError:", isError(new RangeError)); console.log("SyntaxError:", isError(new SyntaxError)); console.log("Object:", isError({})); console.log("Array:", isError([]));

此行為由 ECMAScript 語言規范保證。

Object.prototype.toString

當調用 toString 方法時,采取以下步驟:

  1. 如果 this 值未定義,則返回“[object Undefined]”。
  2. 如果 this 值為空,則返回“[object Null]”。
  3. 讓 O 成為調用 ToObject 並將 this 值作為參數傳遞的結果。
  4. 令 class 為 O 的 [[Class]] 內部屬性的值。
  5. 返回字符串值,該值是連接三個字符串“[object”、class 和“]”的結果。

錯誤實例的屬性

Error 實例從 Error 原型對象繼承屬性,它們的[[Class]]內部屬性值為“Error”。 錯誤實例沒有特殊屬性。

TypeScript解決方案

你可以定義一個用戶定義的類型守衛,只需要定義一個返回類型為類型謂詞的 function

您可以檢查變量是否是這樣的錯誤

const isError = (err: unknown): err is Error => err instanceof Error;

然后在里面嘗試捕獲驗證這樣的

try {
  login(username, password);
} catch (err) {
  if (isError(err)) {
  console.log(err.message);
}

您可以使用 obj.constructor.name 檢查對象的“類” https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name#Function_names_in_classes

例如

var error = new Error("ValidationError");
console.log(error.constructor.name);

上面的行將記錄“錯誤”,它是對象的類名。 如果該類不使用名稱為“name”的屬性,則這可以與 javascript 中的任何類一起使用

感謝@Trott 提供您的代碼,我只是使用了相同的代碼並添加了一個實時工作示例以供他人使用。

 <html> <body > <p>The **instanceof** operator returns true if the specified object is an instance of the specified object.</p> <script> var myError = new Error("TypeError: Cannot set property 'innerHTML' of null"); // error type when element is not defined myError instanceof Error // true function test(){ var v1 = document.getElementById("myid").innerHTML ="zunu"; // to change with this try { var v1 = document.getElementById("myidd").innerHTML ="zunu"; // exception caught } catch (e) { if (e instanceof Error) { console.error(e.name + ': ' + e.message) // error will be displayed at browser console } } finally{ var v1 = document.getElementById("myid").innerHTML ="Text Changed to Zunu"; // finally innerHTML changed to this. } } </script> <p id="myid">This text will change</p> <input type="button" onclick="test();"> </body> </html>

對於那些正在尋找某種“官方”方式(就像我一樣)的人,這就是MDN 推薦的

try {
  myRoutine();
} catch (e) {
  if (e instanceof RangeError) {
    // statements to handle this very common expected error
  } else {
    throw e;  // re-throw the error unchanged
  }
}

或者將其用於不同類型的錯誤

function isError(val) {
  return (!!val && typeof val === 'object')
    && ((Object.prototype.toString.call(val) === '[object Error]')
      || (typeof val.message === 'string' && typeof val.name === 'string'))
}

只需使用error.name

 function _err(type = false) { if(type) { throw new TypeError('Oh crap!') } throw new Error('Oh crap!') } try { _err(true) } catch (error) { console.log(typeof error.name, error.name, error.name === 'TypeError') } try { _err() } catch (error) { console.log(typeof error.name, error.name, error.name === 'Error') }

您可以進一步從@iota 獲取答案,並通過getPrototypeOf()或已棄用的__proto__屬性檢查測試對象的內部[[Prototype]]屬性。

如果對象是一個錯誤,它繼承自Error.prototype 所以也許是這樣的:

// the object you want to check 
const objectToCheck = new Error();

// current way
console.log(Object.getPrototypeOf(objectToCheck) === Error.prototype);  /* true*/

// deprecated way
console.log(objectToCheck.__proto__ === Error.prototype);  /* true */

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM