出于某种原因,看起来构造函数委派在以下代码段中不起作用:
function NotImplementedError() {
Error.apply(this, arguments);
}
NotImplementedError.prototype = new Error();
var nie = new NotImplementedError("some message");
console.log("The message is: '"+nie.message+"'")
运行此选项会产生The message is: ''
。有关为什么,或者是否有更好的方法来创建新的Error
子类的任何想法? apply
是否存在我不知道的原生Error
构造函数的问题?
答案 0 :(得分:186)
更新您的代码,将您的原型分配给Error.prototype和instanceof,并且您的断言可以正常工作。
function NotImplementedError(message) {
this.name = "NotImplementedError";
this.message = (message || "");
}
NotImplementedError.prototype = Error.prototype;
但是,我只想抛出你自己的对象,只需检查name属性。
throw {name : "NotImplementedError", message : "too lazy to implement"};
根据评论进行修改
在查看评论并试图记住为什么我会将原型分配给Error.prototype
代替new Error()
,就像Nicholas Zakas在article中所做的那样,我创建了一个jsFiddle使用以下代码:
function NotImplementedError(message) {
this.name = "NotImplementedError";
this.message = (message || "");
}
NotImplementedError.prototype = Error.prototype;
function NotImplementedError2(message) {
this.message = (message || "");
}
NotImplementedError2.prototype = new Error();
try {
var e = new NotImplementedError("NotImplementedError message");
throw e;
} catch (ex1) {
console.log(ex1.stack);
console.log("ex1 instanceof NotImplementedError = " + (ex1 instanceof NotImplementedError));
console.log("ex1 instanceof Error = " + (ex1 instanceof Error));
console.log("ex1.name = " + ex1.name);
console.log("ex1.message = " + ex1.message);
}
try {
var e = new NotImplementedError2("NotImplementedError2 message");
throw e;
} catch (ex1) {
console.log(ex1.stack);
console.log("ex1 instanceof NotImplementedError2 = " + (ex1 instanceof NotImplementedError2));
console.log("ex1 instanceof Error = " + (ex1 instanceof Error));
console.log("ex1.name = " + ex1.name);
console.log("ex1.message = " + ex1.message);
}
控制台输出就是这个。
undefined
ex1 instanceof NotImplementedError = true
ex1 instanceof Error = true
ex1.name = NotImplementedError
ex1.message = NotImplementedError message
Error
at window.onload (http://fiddle.jshell.net/MwMEJ/show/:29:34)
ex1 instanceof NotImplementedError2 = true
ex1 instanceof Error = true
ex1.name = Error
ex1.message = NotImplementedError2 message
这确认了我遇到的“问题”是错误的堆栈属性是创建new Error()
的行号,而不是throw e
发生的位置。但是,具有影响Error对象的NotImplementedError.prototype.name = "NotImplementedError"
行的副作用可能会更好。
另外,请注意NotImplementedError2
,当我没有明确设置.name
时,它等于“错误”。但是,正如评论中所提到的,因为该版本将原型设置为new Error()
,我可以设置NotImplementedError2.prototype.name = "NotImplementedError2"
并保持正常。
答案 1 :(得分:85)
所有上述答案都非常糟糕 - 真的。即便是107人的!真正的答案是这里的人:
Inheriting from the Error object - where is the message property?
TL; DR:
一个。 message
未设置的原因是Error
是一个返回新Error对象并且不以任何方式操纵this
的函数。
B中。这样做的方法是从构造函数返回apply的结果,以及以通常复杂的javascripty方式设置原型:
function MyError() {
var temp = Error.apply(this, arguments);
temp.name = this.name = 'MyError';
this.message = temp.message;
if(Object.defineProperty) {
// getter for more optimizy goodness
/*this.stack = */Object.defineProperty(this, 'stack', {
get: function() {
return temp.stack
},
configurable: true // so you can change it if you want
})
} else {
this.stack = temp.stack
}
}
//inherit prototype using ECMAScript 5 (IE 9+)
MyError.prototype = Object.create(Error.prototype, {
constructor: {
value: MyError,
writable: true,
configurable: true
}
});
var myError = new MyError("message");
console.log("The message is: '" + myError.message + "'"); // The message is: 'message'
console.log(myError instanceof Error); // true
console.log(myError instanceof MyError); // true
console.log(myError.toString()); // MyError: message
console.log(myError.stack); // MyError: message \n
// <stack trace ...>
//for EMCAScript 4 or ealier (IE 8 or ealier), inherit prototype this way instead of above code:
/*
var IntermediateInheritor = function() {};
IntermediateInheritor.prototype = Error.prototype;
MyError.prototype = new IntermediateInheritor();
*/
你可能会做一些诡计来枚举tmp
错误的所有非可枚举属性来设置它们,而不是只显式设置stack
和message
,但是诡计不是在&lt; 9
答案 2 :(得分:20)
如果有人对如何创建自定义错误感到好奇和获取堆栈跟踪:
function CustomError(message) {
this.name = 'CustomError';
this.message = message || '';
var error = new Error(this.message);
error.name = this.name;
this.stack = error.stack;
}
CustomError.prototype = Object.create(Error.prototype);
try {
throw new CustomError('foobar');
}
catch (e) {
console.log('name:', e.name);
console.log('message:', e.message);
console.log('stack:', e.stack);
}
答案 3 :(得分:17)
在ES2015中,您可以使用class
干净地执行此操作:
class NotImplemented extends Error {
constructor(message = "", ...args) {
super(message, ...args);
this.message = message + " has not yet been implemented.";
}
}
这不会修改全局Error
原型,允许您自定义message
,name
和其他属性,并正确捕获堆栈。它也非常易读。
当然,如果您的代码将在较旧的浏览器上运行,则可能需要使用babel
之类的工具。
答案 4 :(得分:7)
标准的这一部分可以解释Error.apply
调用未初始化对象的原因:
15.11.1将错误构造函数称为函数
当Error被调用为函数而不是构造函数时,它会创建和 初始化一个新的Error对象。因此函数调用Error(...)是 相当于对象创建表达式new Error(...)with 相同的论点。
在这种情况下,Error
函数可能确定它不是作为构造函数调用的,因此它返回一个新的Error实例,而不是初始化this
对象。
使用以下代码进行测试似乎表明这实际上正在发生的事情:
function NotImplementedError() {
var returned = Error.apply(this, arguments);
console.log("returned.message = '" + returned.message + "'");
console.log("this.message = '" + this.message + "'");
}
NotImplementedError.prototype = new Error();
var nie = new NotImplementedError("some message");
运行此命令时会生成以下输出:
returned.message = 'some message'
this.message = ''
答案 5 :(得分:6)
我遇到了类似的问题。我的错误必须是instanceof
Error
和NotImplemented
,并且还需要在控制台中生成一致的回溯。
我的解决方案:
var NotImplemented = (function() {
var NotImplemented, err;
NotImplemented = (function() {
function NotImplemented(message) {
var err;
err = new Error(message);
err.name = "NotImplemented";
this.message = err.message;
if (err.stack) this.stack = err.stack;
}
return NotImplemented;
})();
err = new Error();
err.name = "NotImplemented";
NotImplemented.prototype = err;
return NotImplemented;
}).call(this);
// TEST:
console.log("instanceof Error: " + (new NotImplemented() instanceof Error));
console.log("instanceof NotImplemented: " + (new NotImplemented() instanceofNotImplemented));
console.log("message: "+(new NotImplemented('I was too busy').message));
throw new NotImplemented("just didn't feel like it");
使用node.js运行的结果:
instanceof Error: true
instanceof NotImplemented: true
message: I was too busy
/private/tmp/t.js:24
throw new NotImplemented("just didn't feel like it");
^
NotImplemented: just didn't feel like it
at Error.NotImplemented (/Users/colin/projects/gems/jax/t.js:6:13)
at Object.<anonymous> (/Users/colin/projects/gems/jax/t.js:24:7)
at Module._compile (module.js:449:26)
at Object.Module._extensions..js (module.js:467:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Module.runMain (module.js:487:10)
at process.startup.processNextTick.process._tickCallback (node.js:244:9)
错误通过了我的所有3个条件,虽然stack
属性是非标准的,it is supported in most newer browsers在我的情况下是可以接受的。
答案 6 :(得分:6)
function InvalidValueError(value, type) {
this.message = "Expected `" + type.name + "`: " + value;
var error = new Error(this.message);
this.stack = error.stack;
}
InvalidValueError.prototype = new Error();
InvalidValueError.prototype.name = InvalidValueError.name;
InvalidValueError.prototype.constructor = InvalidValueError;
答案 7 :(得分:4)
Accoring to Joyent你不应该搞乱堆栈属性(我在这里给出了很多答案),因为它会对性能产生负面影响。这是他们所说的:
堆叠:一般来说,不要乱用这个。甚至不要增加它。 V8仅在有人实际读取属性时才计算它,这可以显着提高可处理错误的性能。如果您只是为了扩充它而阅读该属性,即使您的调用者不需要堆栈,您最终也会支付费用。
我喜欢并且想提及their idea of wrapping the original error,这是传递堆栈的一个很好的替代品。
考虑到上面提到的,我在这里是如何创建自定义错误的:
function RError(options) {
options = options || {}; // eslint-disable-line no-param-reassign
this.name = options.name;
this.message = options.message;
this.cause = options.cause;
// capture stack (this property is supposed to be treated as private)
this._err = new Error();
// create an iterable chain
this.chain = this.cause ? [this].concat(this.cause.chain) : [this];
}
RError.prototype = Object.create(Error.prototype, {
constructor: {
value: RError,
writable: true,
configurable: true
}
});
Object.defineProperty(RError.prototype, 'stack', {
get: function stack() {
return this.name + ': ' + this.message + '\n' + this._err.stack.split('\n').slice(2).join('\n');
}
});
Object.defineProperty(RError.prototype, 'why', {
get: function why() {
var _why = this.name + ': ' + this.message;
for (var i = 1; i < this.chain.length; i++) {
var e = this.chain[i];
_why += ' <- ' + e.name + ': ' + e.message;
}
return _why;
}
});
// usage
function fail() {
throw new RError({
name: 'BAR',
message: 'I messed up.'
});
}
function failFurther() {
try {
fail();
} catch (err) {
throw new RError({
name: 'FOO',
message: 'Something went wrong.',
cause: err
});
}
}
try {
failFurther();
} catch (err) {
console.error(err.why);
console.error(err.stack);
console.error(err.cause.stack);
}
class RError extends Error {
constructor({name, message, cause}) {
super();
this.name = name;
this.message = message;
this.cause = cause;
}
[Symbol.iterator]() {
let current = this;
let done = false;
const iterator = {
next() {
const val = current;
if (done) {
return { value: val, done: true };
}
current = current.cause;
if (!val.cause) {
done = true;
}
return { value: val, done: false };
}
};
return iterator;
}
get why() {
let _why = '';
for (const e of this) {
_why += `${_why.length ? ' <- ' : ''}${e.name}: ${e.message}`;
}
return _why;
}
}
// usage
function fail() {
throw new RError({
name: 'BAR',
message: 'I messed up.'
});
}
function failFurther() {
try {
fail();
} catch (err) {
throw new RError({
name: 'FOO',
message: 'Something went wrong.',
cause: err
});
}
}
try {
failFurther();
} catch (err) {
console.error(err.why);
console.error(err.stack);
console.error(err.cause.stack);
}
我已将我的解决方案放入模块中,此处为:https://www.npmjs.com/package/rerror
答案 8 :(得分:2)
class NotImplementedError extends Error {
constructor(message) {
super(message);
this.message = message;
}
}
NotImplementedError.prototype.name = 'NotImplementedError';
module.exports = NotImplementedError;
和
try {
var e = new NotImplementedError("NotImplementedError message");
throw e;
} catch (ex1) {
console.log(ex1.stack);
console.log("ex1 instanceof NotImplementedError = " + (ex1 instanceof NotImplementedError));
console.log("ex1 instanceof Error = " + (ex1 instanceof Error));
console.log("ex1.name = " + ex1.name);
console.log("ex1.message = " + ex1.message);
}
这只是this答案的类表示。
输出
NotImplementedError: NotImplementedError message
...stacktrace
ex1 instanceof NotImplementedError = true
ex1 instanceof Error = true
ex1.name = NotImplementedError
ex1.message = NotImplementedError message
答案 9 :(得分:2)
我使用构造函数模式来创建新的错误对象。我定义了原型链,例如Error
实例。请参阅MDN Error constructor参考。
您可以在此 gist 。
上查看此代码段// Creates user-defined exceptions
var CustomError = (function() {
'use strict';
//constructor
function CustomError() {
//enforces 'new' instance
if (!(this instanceof CustomError)) {
return new CustomError(arguments);
}
var error,
//handles the arguments object when is passed by enforcing a 'new' instance
args = Array.apply(null, typeof arguments[0] === 'object' ? arguments[0] : arguments),
message = args.shift() || 'An exception has occurred';
//builds the message with multiple arguments
if (~message.indexOf('}')) {
args.forEach(function(arg, i) {
message = message.replace(RegExp('\\{' + i + '}', 'g'), arg);
});
}
//gets the exception stack
error = new Error(message);
//access to CustomError.prototype.name
error.name = this.name;
//set the properties of the instance
//in order to resemble an Error instance
Object.defineProperties(this, {
stack: {
enumerable: false,
get: function() { return error.stack; }
},
message: {
enumerable: false,
value: message
}
});
}
// Creates the prototype and prevents the direct reference to Error.prototype;
// Not used new Error() here because an exception would be raised here,
// but we need to raise the exception when CustomError instance is created.
CustomError.prototype = Object.create(Error.prototype, {
//fixes the link to the constructor (ES5)
constructor: setDescriptor(CustomError),
name: setDescriptor('JSU Error')
});
function setDescriptor(value) {
return {
configurable: false,
enumerable: false,
writable: false,
value: value
};
}
//returns the constructor
return CustomError;
}());
CustomError构造函数可以接收许多参数来构建消息,例如
var err1 = new CustomError("The url of file is required"),
err2 = new CustomError("Invalid Date: {0}", +"date"),
err3 = new CustomError("The length must be greater than {0}", 4),
err4 = new CustomError("Properties .{0} and .{1} don't exist", "p1", "p2");
throw err4;
这就是自定义错误的外观:
答案 10 :(得分:2)
我只需实现类似的东西,发现堆栈在我自己的错误实现中丢失了。我必须做的是创建一个虚拟错误并从中检索堆栈:
My.Error = function (message, innerException) {
var err = new Error();
this.stack = err.stack; // IMPORTANT!
this.name = "Error";
this.message = message;
this.innerException = innerException;
}
My.Error.prototype = new Error();
My.Error.prototype.constructor = My.Error;
My.Error.prototype.toString = function (includeStackTrace) {
var msg = this.message;
var e = this.innerException;
while (e) {
msg += " The details are:\n" + e.message;
e = e.innerException;
}
if (includeStackTrace) {
msg += "\n\nStack Trace:\n\n" + this.stack;
}
return msg;
}
答案 11 :(得分:1)
这在Cesium DeveloperError中很好地实现了:
以简化形式:
var NotImplementedError = function(message) {
this.name = 'NotImplementedError';
this.message = message;
this.stack = (new Error()).stack;
}
// Later on...
throw new NotImplementedError();
答案 12 :(得分:1)
这是我的实现方式
class HttpError extends Error {
constructor(message, code = null, status = null, stack = null, name = null) {
super();
this.message = message;
this.status = 500;
this.name = name || this.constructor.name;
this.code = code || `E_${this.name.toUpperCase()}`;
this.stack = stack || null;
}
static fromObject(error) {
if (error instanceof HttpError) {
return error;
}
else {
const { message, code, status, stack } = error;
return new ServerError(message, code, status, stack, error.constructor.name);
}
}
expose() {
if (this instanceof ClientError) {
return { ...this };
}
else {
return {
name: this.name,
code: this.code,
status: this.status,
}
}
}
}
class ServerError extends HttpError {}
class ClientError extends HttpError { }
class IncorrectCredentials extends ClientError {
constructor(...args) {
super(...args);
this.status = 400;
}
}
class ResourceNotFound extends ClientError {
constructor(...args) {
super(...args);
this.status = 404;
}
}
示例用法1:
app.use((req, res, next) => {
try {
invalidFunction();
}
catch (err) {
const error = HttpError.fromObject(err);
return res.status(error.status).send(error.expose());
}
});
示例用法2:
router.post('/api/auth', async (req, res) => {
try {
const isLogged = await User.logIn(req.body.username, req.body.password);
if (!isLogged) {
throw new IncorrectCredentials('Incorrect username or password');
}
else {
return res.status(200).send({
token,
});
}
}
catch (err) {
const error = HttpError.fromObject(err);
return res.status(error.status).send(error.expose());
}
});
答案 13 :(得分:1)
构造函数需要像工厂方法一样并返回您想要的内容。如果需要其他方法/属性,可以在返回之前将它们添加到对象中。
function NotImplementedError(message) { return new Error("Not implemented", message); }
x = new NotImplementedError();
虽然我不确定你为什么需要这样做。为什么不使用new Error...
?自定义异常并没有在JavaScript(或者可能是任何无类型语言)中添加太多内容。
答案 14 :(得分:0)
另一种选择,可能不适用于所有环境。至少可以确保它在nodejs 0.8中有效 这种方法使用非标准方式修改内部原型
function myError(msg){
var e = new Error(msg);
_this = this;
_this.__proto__.__proto__ = e;
}
答案 15 :(得分:0)
如果您使用的是Node / Chrome。以下代码段将为您提供符合以下要求的扩展程序。
err instanceof Error
err instanceof CustomErrorType
[CustomErrorType]
[CustomErrorType: message]
if
语句,并且您很高兴。片段
var CustomErrorType = function(message) {
if (Object.defineProperty) {
Object.defineProperty(this, "message", {
value : message || "",
enumerable : false
});
} else {
this.message = message;
}
if (Error.captureStackTrace) {
Error.captureStackTrace(this, CustomErrorType);
}
}
CustomErrorType.prototype = new Error();
CustomErrorType.prototype.name = "CustomErrorType";
用法
var err = new CustomErrorType("foo");
输出
var err = new CustomErrorType("foo");
console.log(err);
console.log(err.stack);
[CustomErrorType: foo]
CustomErrorType: foo
at Object.<anonymous> (/errorTest.js:27:12)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Function.Module.runMain (module.js:497:10)
at startup (node.js:119:16)
at node.js:906:3
/errorTest.js:30
throw err;
^
CustomErrorType: foo
at Object.<anonymous> (/errorTest.js:27:12)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Function.Module.runMain (module.js:497:10)
at startup (node.js:119:16)
at node.js:906:3
答案 16 :(得分:0)
以无法使用instanceof
为代价,以下内容保留了原始堆栈跟踪,并且不使用任何非标准技巧。
// the function itself
var fixError = function(err, name) {
err.name = name;
return err;
}
// using the function
try {
throw fixError(new Error('custom error message'), 'CustomError');
} catch (e) {
if (e.name == 'CustomError')
console.log('Wee! Custom Error! Msg:', e.message);
else
throw e; // unhandled. let it propagate upwards the call stack
}
答案 17 :(得分:0)
我喜欢这样做,因此消息在堆栈跟踪或toString中是相同的,并且我可以只传递名称或名称和消息。例如,在引发HTTP错误时很有用,您的处理程序仅可以ListNode *head = nullptr, **ptail = &head;
cout << "Hit 'esc' when you are done.\n";
for(char c; (c = _getche()) != 27;) {
auto node = new ListNode{c, nullptr}; // allocate and initialize a new node
*ptail = node; // append to the end of the list
ptail = &node->next; // move the end of list to the new node
}
//Display linked list
cout << "Here is what you have typed so far:\n";
for(auto next = head; next; next = next->next)
_putch(next->c);
向用户发送,它将优雅地处理您的错误或其他任何错误。
error.toString()
答案 18 :(得分:0)
以下内容来自Mozilla官方文档Error。
function NotImplementedError(message) {
var instance = new Error(message);
instance.name = 'NotImplementedError';
Object.setPrototypeOf(instance, Object.getPrototypeOf(this));
if (Error.captureStackTrace) {
Error.captureStackTrace(instance, NotImplementedError);
}
return instance;
}
NotImplementedError.prototype = Object.create(Error.prototype, {
constructor: {
value: Error,
enumerable: false,
writable: true,
configurable: true
}
});
答案 19 :(得分:-1)
为用户定义的错误类型的每个实例尝试一个新的原型对象。它允许instanceof
检查像往常一样加上类型,并在Firefox和V8(Chome,nodejs)中正确报告消息。
function NotImplementedError(message){
if(NotImplementedError.innercall===undefined){
NotImplementedError.innercall = true;
NotImplementedError.prototype = new Error(message);
NotImplementedError.prototype.name = "NotImplementedError";
NotImplementedError.prototype.constructor = NotImplementedError;
return new NotImplementedError(message);
}
delete NotImplementedError.innercall;
}
请注意,额外的条目将在正确的堆栈之前。
答案 20 :(得分:-1)
这是最快的方法:
p { display: initial; }
答案 21 :(得分:-3)
更简单的方法。您可以使您的对象继承自Error对象。 例如:
function NotImplementError(message)
{
this.message = message;
Error.call();
Error.call(message);
}
我们正在做的是使用函数call()来调用Error类的构造函数,因此与在其他面向对象语言中实现类继承基本相同。
答案 22 :(得分:-3)
MDN有excellent example:
try {
throw new Error('Whoops!');
} catch (e) {
console.log(e.name + ': ' + e.message);
}