检查JS中的typeof错误

在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操作符有任何帮助吗?

242915 次浏览

你可以使用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操作符可能会失败,特别是在前端开发中,当跨越iframes等边界时。看到的: https://github.com/mrdoob/three.js/issues/5886 < / p >

如果你能接受鸭子输入,这应该很好:

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

我个人更喜欢静态类型的语言,但如果您使用的是动态语言,最好是接受动态语言的本质,而不是强迫它像静态类型的语言一样运行。

如果你想要更精确一点,你可以这样做:

   let isError = (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

或者对不同类型的错误使用这个

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

你可以使用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);

上面的行将记录“Error”,这是对象的类名。这可以用于javascript中的任何类,如果类没有使用名称为“name”的属性

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

你可以使用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. 返回String值,该值是连接三个String &;[object ", class和"]"的结果。

错误实例的属性:

错误实例从错误原型对象继承属性,它们的[[Class]]内部属性值是"Error"。错误实例没有特殊属性。

对于那些正在寻找某种“官方”方式的人(就像我一样),这是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
}
}

只要使用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 */

打印稿的解决方案

你可以定义用户定义的类型保护,只需要定义一个返回类型为类型谓词的函数

你可以像这样检查一个变量是否有错误

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

然后在try catch中像这样验证它

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