正确的非字符串Javascript异常
不知何故,这并不像是50年编程语言发展的顶峰:正确的非字符串Javascript异常,javascript,exception,exception-handling,ecmascript-5,Javascript,Exception,Exception Handling,Ecmascript 5,不知何故,这并不像是50年编程语言发展的顶峰: throw "My exception message here"; 在Javascript中执行异常的正确方法是什么 它们可以被识别(instanceof) 除了默认消息和堆栈跟踪之外,它们还可以携带其他有效负载 它们“子类化”基本异常,以便调试控制台等可以提取有关异常的有意义信息 可能的嵌套异常(将异常转换为另一个异常):如果需要捕获异常并重新生成新异常,则原始堆栈跟踪将被保留,并可由调试工具进行有意义的读取 它们遵循Javascrip
throw "My exception message here";
在Javascript中执行异常的正确方法是什么
- 它们可以被识别(instanceof)
- 除了默认消息和堆栈跟踪之外,它们还可以携带其他有效负载
- 它们“子类化”基本异常,以便调试控制台等可以提取有关异常的有意义信息
- 可能的嵌套异常(将异常转换为另一个异常):如果需要捕获异常并重新生成新异常,则原始堆栈跟踪将被保留,并可由调试工具进行有意义的读取
- 它们遵循Javascript最佳实践
- JavaScript中的基本“异常”是内置的
错误对象:
throw new Error("My exception message here");
您可以将自定义异常定义为:
function CustomError(message) {
this.message = message;
}
CustomError.prototype = new Error();
CustomError.prototype.constructor = CustomError;
使用instanceof
检查异常类型。还有一个。您可以通过调用。
错误
对象可以有消息和名称。捕获时,您可以检查特定名称,也可以通过继承错误
原型来创建自定义错误类型。这使得不同错误类型之间的instanceof
的使用有所不同
// Create a new object, that prototypally inherits from the Error constructor.
function MyError(message) {
this.message = message || "Default Message";
}
MyError.prototype = new Error();
MyError.prototype.constructor = MyError;
try {
throw new MyError();
} catch (e) {
console.log(e.name); // "MyError"
console.log(e.message); // "Default Message"
}
try {
throw new MyError("custom message");
} catch (e) {
console.log(e.name); // "MyError"
console.log(e.message); // "custom message"
}
示例取自:抛出新错误(“消息”)代码>
或者,如果您想更具体地使用
确保抛出真正的错误很重要,因为它们包含堆栈跟踪。抛出字符串是愚蠢的,因为它没有附加任何元数据
您还可以对错误进行子类化
// for some sensible implementation of extend
// https://gist.github.com/1441105#file_1pd.js
var MyError = extend(Object.create(Error.prototype), {
...
});
你不能这样做,并满足问题的要求
为什么?
问题是获取堆栈。本机错误对象(从现在起为NativeError)在调用其构造函数时初始化堆栈。要在MyError(错误子类)中获取堆栈,必须在MyError的构造函数中调用NativeConstructor。因此,您的MyError类如下所示:
function MyError(msg) {
Error.call(this, msg);
}
但是,这是行不通的。因为根据规范:
“如果您将Error作为函数调用,它将返回一个新的Error对象”
它创建了一个您不需要的错误对象,而不是很好地初始化您的自定义错误类。我还没有找到调用NativeError构造函数并让它初始化MyError子类的方法
并不是所有的东西都丢了
如果我们放松了最初的问题要求,忘记了“instanceof”来测试异常类(不管怎样,Java也是如此),而是使用“name”,那么就可以完成。只需将MyError声明为:
function MyError(msg, customArg) {
var e = new Error(msg);
e.name = "MyError";
e.custom = customArg;
return e;
}
我就是这么做的。不要打开“instanceof”,而是打开“name”。JavaScript真的没有这些吗?你能在JS中将任何对象序列化为字符串吗?@VladislavZorov:是的,Javascript有这些。在问题的开头阐明了嵌套异常的必要性。任何关于JavaScript的讨论都应该这样开始代码>偏好x.prototype=Object.create(y.prototype)
@Raynos在浏览器环境中Object.create
可能不可用,您需要一个polyfill。在JavaScript>=1.8.5的环境中,我同意。最好是polyfill Object.create,然后使用newy()
developer.mozilla.org提供的polyfill只是x.prototype=y.prototype
。这不会创建一个引用吗?@Eliasdx:x.prototype=y.prototype
不符合您的要求(即,将x.ptototype设置为从y.prototype继承的空对象)。再次检查。避免在CustomError
赋值中调用newerror
,因为它在CustomError
上调用构造函数,而留下堆栈跟踪数据。支持使用原型扩展名(CustomError.prototype=Object.create(Error);
)@Raynos为什么使用Object.create(Error)而不是new Error?你能澄清两者之间的区别吗?“对于extend的合理实施”什么?我不明白。Javascript扩展对象模式是许多Javascript框架实现的一种常见设计模式,例如jQuery@Mikko:是的,我知道,但我不明白这句话。NiklasBaumstark,这是一个免责声明,说我希望在环境中存在一些合理的extend实现。LOL@extend也是一种设计模式。这是一个实用函数-我想说扩展是一种模式,因为它通常以许多原型方式被利用,而不限于一个库/函数。有些框架也调用extend()函数。并非所有库都尊重name
变量。例如,需要自定义错误prototype
从error.prototype
下降。事实上,根据对象的状态,如果您不100%小心,您可能会遇到麻烦,因为依赖原型链时名称可能会发生变异,因此不那么脆弱,更符合OOP习惯。