检查JS中的typeof错误


153

在JS中,似乎无法检查传递给函数的参数是否实际上是'error'类型或Error实例。

例如,这是无效的:

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

那么确定参数是否为Error实例的最佳方法是什么?

instanceof操作员有帮助吗?


10
是的,请使用err instanceof Error
colecmc

2
如果错误可能是来自框架或其他窗口中的代码,@ colecmc不会有问题吗?在这种情况下,将有不同的原型Error对象,而instanceof将无法按预期工作。(见developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
杜安

@Doin,我不这么认为。它将仅验证实际的错误对象。
colecmc '16

1
@colecmc,我想您会发现,如果您抛出err(说)一个iframe,然后将其传递给父窗口进行处理,则会得到(err instanceof Error) === false。这是因为iframe及其父窗口具有不同的,不同的Error对象原型。同样,将诸如obj = {};will 这样的对象传递给在另一个窗口中运行的函数yeild (obj instanceof Object)===false。(即使在最糟糕的情况下,在IE中,如果在obj的窗口被破坏或导航后仍保留对obj的引用,则尝试像调用对象原型fns一样obj.hasOwnProperty()会抛出错误!)
Doin

您如何检查错误类型?即catch((err)=>{if (err === ENOENT)返回ENOENT is not defined错误?
oldboy

Answers:


261

您可以使用instanceof运算符(但请参见下面的警告!)。

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

如果错误是在与进行检查的位置不同的窗口/框架/ iframe中引发的,则上述方法将无效。在这种情况下,instanceof Error即使对于Error对象,检查也将返回false 。在这种情况下,最简单的方法是鸭式打字。

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

但是,如果您有包含stackmessage属性的非错误对象,则鸭子类型可能会产生误报。


1
@AurélienRibon它与ReferenceError实例正常工作。您正在检查全局ReferenceError对象。试试这个:try { foo } catch (e) { console.log(e instanceof Error) }它记录true。如果ReferenceError由于某种原因试图检查全局对象,则可以使用Error.isPrototypeOf(ReferenceError)
Trott

1
@AurélienRibon(嗯,是的,不确定是不是您说的“这不适用于ReferenceError”还是不正确,或者您只是指出“这不适用于全局ReferenceError对象”这是绝对正确的,尽管我很难解决可能要检查的情况,但这可能更多地说明了我缺乏想象力,而不是用例的有效性。
Trott

哈哈,对不起,我只是陷入一个奇怪的错误,我的所有ReferenceError实例都不是的实例Error。这是由于对vm.runInNewContext()in节点的调用,在该节点中重新定义了所有标准原型。我所有的结果都不是标准对象的实例。我一直在寻找有关此内容的信息,并且陷入了这个
话题

1
您可以尝试const error = (err instanceof Error || err instanceof TypeError) ? err : new Error(err.message ? err.message : err);
Aamir Afridi

您如何检查其是否instanceof为特定类型的错误?
老男孩

25

我问了最初的问题-@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';
    }

3
在编写实用程序函数或库时,我更喜欢此版本。它不会将用户限制在一个特定的全局上下文中,也可以正确处理JSON中的反序列化错误。
尼克

谢谢,是的,在很多情况下,如果它看起来像一个错误,我们可以将其视为一个错误。在某些情况下,完全可以接受鸭子类型,在某些情况下完全不能接受,在这种情况下,完全可以。
亚历山大·米尔斯

我使用调试器进行了一些调试,堆栈和消息确实确实是Error实例上仅有的两个非本机属性。
亚历山大·米尔斯

1
@Trott您可能会对instanceof某些情况下的操作员失败感兴趣,请参阅链接的文章。
亚历山大·米尔斯

1
这实际上是最简单的,因此与不同类型的错误有效(即ErrorReferenceError...)。在我的环境中,instanceof失败在许多情况下都是惨痛的。
亚历克西斯威尔克

10
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

2

您可以使用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([]));


1

您可以使用obj.constructor.name来检查对象的“类” https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/name#Function_names_in_classes

例如

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

上一行将记录“错误”,它是对象的类名称。如果该类未使用名称为“ name”的属性,则可以与javascript中的任何类一起使用


当缩小代码并使用错误子类时,这是不可靠的
felixfbecker

1

感谢@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>


0

或者将其用于不同类型的错误

function isError(val) {
  return (!!val && typeof val === 'object')
    && ((Object.prototype.toString.call(val) === '[object Error]')
      || (typeof val.message === 'string' && typeof val.name === 'string'))
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.