检查 JS 中的 typeof 错误
Posted
技术标签:
【中文标题】检查 JS 中的 typeof 错误【英文标题】:checking for typeof error in JS 【发布时间】:2015-08-08 18:13:59 【问题描述】:在 JS 中,似乎无法检查传递给函数的参数实际上是“错误”类型还是错误实例。
例如,这是无效的:
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
运算符有什么帮助吗?
【问题讨论】:
是的,使用err instanceof Error
@colecmc 如果错误可能来自框架或另一个窗口中的代码,那不会有问题吗?在这种情况下,会有不同的原型 Error 对象,并且 instanceof 不会按预期工作。 (见developer.mozilla.org/en-US/docs/Web/javascript/Reference/…)
@Doin,我不这么认为。它只会验证实际的错误对象。
@colecmc,我想你会发现如果你在(比如说)一个 iframe 中抛出了err
,然后将它传递给父窗口进行处理,你会得到@987654329 @。这是因为 iframe 及其父窗口具有不同的 Error
对象原型。类似地,像obj = ;
这样的对象,当传递给在不同窗口中运行的函数时,会产生(obj instanceof Object)===false
。 (更糟糕的是,在 IE 中,如果您在 obj 的窗口被销毁或导航后保留对 obj 的引用,则尝试像 obj.hasOwnProperty()
这样调用对象原型 fns 会引发错误!)
如何检查错误类型?即catch((err)=>if (err === ENOENT)
返回ENOENT is not defined
错误?
【参考方案1】:
您可以使用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
但是,如果您有包含stack
和message
属性的非错误对象,则duck-typing 可能会产生误报。
【讨论】:
@AurélienRibon 它适用于ReferenceError
实例。您正在检查全局 ReferenceError
对象。试试这个:try foo catch (e) console.log(e instanceof Error)
它记录true
。如果您出于某种原因尝试检查全局 ReferenceError
对象,则可以使用 Error.isPrototypeOf(ReferenceError)
@AurélienRibon(嗯,还有,是的,不确定您是否在说“这不适用于 ReferenceError”,这是不正确的,或者您只是指出“这不会” t 与全局 ReferenceError 对象一起工作”这是绝对正确的,虽然我很难想出一个可以检查的情况,但这可能更多地说明我缺乏想象力而不是用例的有效性)。
哈哈,对不起那些家伙,我刚刚陷入了一个奇怪的错误,我的所有ReferenceError
实例都不是Error
的实例。这是由于在节点中调用了vm.runInNewContext()
,所有标准原型都被重新定义。我所有的结果都不是标准对象的实例。我一直在寻找这个,并陷入了这个线程:)
你可以试试const error = (err instanceof Error || err instanceof TypeError) ? err : new Error(err.message ? err.message : err);
你如何检查它是否是 instanceof
特定类型的错误?【参考方案2】:
我问了最初的问题 - @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';
【讨论】:
在编写实用函数或库时,我更喜欢这个版本。它不会将用户限制在一个特定的全局上下文中,并且还可以正确处理来自 JSON 的反序列化错误。 谢谢,是的,在很多情况下,如果它看起来像一个错误,我们可以将其视为一个错误。在某些情况下,鸭子打字是完全可以接受的,在某些情况下它根本不可接受,在这种情况下,完全可以。 我使用调试器进行了一些调试,堆栈和消息确实似乎是错误实例上仅有的两个非本机属性。 @Trott 您可能有兴趣了解instanceof
运算符在某些情况下会失败,请参阅链接文章。
这实际上是最简单的,因此它适用于不同类型的错误(即Error
,ReferenceError
,...)。在我的环境中,instanceof
在许多情况下都失败了。【参考方案3】:
您可以使用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方法时,会采取以下步骤:
如果 this 值未定义,则返回“[object Undefined]”。 如果this值为null,则返回“[object Null]”。 令 O 为调用 ToObject 并将 this 值作为参数传递的结果。 令 class 为 O 的 [[Class]] 内部属性的值。 返回字符串值,它是三个字符串“[object”、class 和“]”连接的结果。
Properties of Error Instances:
错误实例从错误原型对象继承属性,其
[[Class]]
内部属性值为“错误”。错误实例没有特殊属性。
【讨论】:
我不确定我是否喜欢这个。我不知道是否有任何标准规定,当字符串化时,错误必须完全是这种形式。我认为这将取决于实施...... @Aaron 这不是真的。我已经用 ECMAScript 语言规范的摘录编辑了我的答案。 这是具有最少(没有?)缺点的最佳解决方案。【参考方案4】: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
【讨论】:
【参考方案5】:你可以像这样检查一个变量是否有错误
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);
【讨论】:
我相信这是一个打字稿解决方案。【参考方案6】:您可以使用 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);
上面的行将记录“错误”,它是对象的类名。这可以与 javascript 中的任何类一起使用,如果该类没有使用名为“name”的属性
【讨论】:
这在缩小代码和使用错误子类时不可靠【参考方案7】:感谢@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>
【讨论】:
嘿,现在是 2020 年 - 请不要在 SO 帖子中使用 var【参考方案8】:对于那些正在寻找一些“官方”方式的人(就像我一样),这是what MDN recommends:
try
myRoutine();
catch (e)
if (e instanceof RangeError)
// statements to handle this very common expected error
else
throw e; // re-throw the error unchanged
【讨论】:
【参考方案9】:或将其用于不同类型的错误
function isError(val)
return (!!val && typeof val === 'object')
&& ((Object.prototype.toString.call(val) === '[object Error]')
|| (typeof val.message === 'string' && typeof val.name === 'string'))
【讨论】:
【参考方案10】:只需使用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')
【讨论】:
【参考方案11】:您可以进一步从@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 */
【讨论】:
以上是关于检查 JS 中的 typeof 错误的主要内容,如果未能解决你的问题,请参考以下文章