简体   繁体   English

检查 JS 中的 typeof 错误

[英]checking for typeof error in JS

In JS it doesn't seem possible to check if an argument passed to a function is actually of the type 'error' or an instance of Error.在 JS 中,似乎无法检查传递给 function 的参数实际上是“错误”类型还是错误实例。

For example, this is not valid:例如,这是无效的:

typeof err === 'error'

since there are only 6 possible types (in the form of strings):因为只有 6 种可能的类型(以字符串的形式):

The typeof operator returns type information as a string. typeof 运算符将类型信息作为字符串返回。 There are six possible values that typeof returns: typeof返回六个可能的值:

"number", "string", "boolean", "object", "function" and "undefined". “数字”、“字符串”、“布尔”、“对象”、“函数”和“未定义”。

MSDN MSDN

But what if I have a simple use case like this:但是,如果我有一个像这样的简单用例怎么办:

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

so what is the best way to determine if an argument is an instance of Error?那么确定参数是否是错误实例的最佳方法是什么?

is the instanceof operator of any help? instanceof运算符有什么帮助吗?

You can use the instanceof operator (but see caveat below!).您可以使用instanceof运算符(但请参阅下面的警告!)。

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

The above won't work if the error was thrown in a different window/frame/iframe than where the check is happening.如果错误是在与检查发生位置不同的窗口/框架/iframe 中引发的,则上述方法将不起作用。 In that case, the instanceof Error check will return false, even for an Error object.在这种情况下, instanceof Error检查将返回 false,即使对于Error对象也是如此。 In that case, the easiest approach is duck-typing.在这种情况下,最简单的方法是鸭子类型。

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

However, duck-typing may produce false positives if you have non-error objects that contain stack and message properties.但是,如果您有包含stackmessage属性的非错误对象,则鸭子类型可能会产生误报。

I asked the original question - @Trott's answer is surely the best.我问了最初的问题——@Trott 的回答肯定是最好的。

However with JS being a dynamic language and with there being so many JS runtime environments, the instanceof operator can fail especially in front-end development when crossing boundaries such as iframes.然而,由于 JS 是一种动态语言,并且有如此多的 JS 运行时环境, instanceof运算符可能会失败,尤其是在前端开发中跨越 iframe 等边界时。 See: https://github.com/mrdoob/three.js/issues/5886参见: https : //github.com/mrdoob/three.js/issues/5886

If you are ok with duck typing, this should be good:如果你对鸭子打字没问题,这应该很好:

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

I personally prefer statically typed languages, but if you are using a dynamic language, it's best to embrace a dynamic language for what it is, rather than force it to behave like a statically typed language.我个人更喜欢静态类型语言,但如果您使用的是动态语言,最好就其本身而言采用动态语言,而不是强迫它表现得像静态类型语言。

if you wanted to get a little more precise, you could do this:如果你想更精确一点,你可以这样做:

   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

Only problem with this is唯一的问题是

myError instanceof Object // true

An alternative to this would be to use the constructor property.另一种方法是使用构造函数属性。

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

Although it should be noted that this match is very specific, for example:虽然需要注意的是,这个匹配是非常具体的,例如:

myError.constructor === TypeError // false

You can use Object.prototype.toString to easily check if an object is an Error , which will work for different frames as well.您可以使用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([]));

This behavior is guaranteed by the ECMAScript Language Specification.此行为由 ECMAScript 语言规范保证。

Object.prototype.toString : Object.prototype.toString

When the toString method is called, the following steps are taken:当调用 toString 方法时,采取以下步骤:

  1. If the this value is undefined, return "[object Undefined]".如果 this 值未定义,则返回“[object Undefined]”。
  2. If the this value is null, return "[object Null]".如果 this 值为空,则返回“[object Null]”。
  3. Let O be the result of calling ToObject passing the this value as the argument.让 O 成为调用 ToObject 并将 this 值作为参数传递的结果。
  4. Let class be the value of the [[Class]] internal property of O.令 class 为 O 的 [[Class]] 内部属性的值。
  5. Return the String value that is the result of concatenating the three Strings "[object ", class, and "]".返回字符串值,该值是连接三个字符串“[object”、class 和“]”的结果。

Properties of Error Instances :错误实例的属性

Error instances inherit properties from the Error prototype object and their [[Class]] internal property value is "Error". Error 实例从 Error 原型对象继承属性,它们的[[Class]]内部属性值为“Error”。 Error instances have no special properties.错误实例没有特殊属性。

TypeScript solution TypeScript解决方案

You can define a user-defined type guard, simply need to define a function whose return type is a type predicate你可以定义一个用户定义的类型守卫,只需要定义一个返回类型为类型谓词的 function

You can check if a variable is error like this您可以检查变量是否是这样的错误

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

then inside try catch validate that like this然后在里面尝试捕获验证这样的

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

You can use obj.constructor.name to check the "class" of an object https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name#Function_names_in_classes您可以使用 obj.constructor.name 检查对象的“类” https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name#Function_names_in_classes

For Example例如

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

The above line will log "Error" which is the class name of the object.上面的行将记录“错误”,它是对象的类名。 This could be used with any classes in javascript, if the class is not using a property that goes by the name "name"如果该类不使用名称为“name”的属性,则这可以与 javascript 中的任何类一起使用

Thanks @Trott for your code, I just used the same code and added with a real time working example for the benefit of others.感谢@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>

For those, who're looking for some 'official' way (like I did), this is what MDN recommends :对于那些正在寻找某种“官方”方式(就像我一样)的人,这就是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
  }
}

Or use this for different types of errors或者将其用于不同类型的错误

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

Just use the error.name只需使用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') }

You can take the answer from @iota a bit further and check the test object's internal [[Prototype]] property via getPrototypeOf() or the deprecated __proto__ property.您可以进一步从@iota 获取答案,并通过getPrototypeOf()或已弃用的__proto__属性检查测试对象的内部[[Prototype]]属性。

If the object is an error, it inherits from Error.prototype .如果对象是一个错误,它继承自Error.prototype So maybe something like this:所以也许是这样的:

// 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