Javascript 从错误对象继承-消息属性在哪里?

Javascript 从错误对象继承-消息属性在哪里?,javascript,Javascript,在Javascript中定义自定义错误对象时,我注意到一个奇怪的行为: function MyError(msg) { Error.call(this, msg); this.name = "MyError"; } MyError.prototype.__proto__ = Error.prototype; var error = new Error("message"); error.message; // "message" var myError = new MyErr

在Javascript中定义自定义错误对象时,我注意到一个奇怪的行为:

function MyError(msg) {
    Error.call(this, msg);
    this.name = "MyError";
}
MyError.prototype.__proto__ = Error.prototype;

var error = new Error("message");
error.message; // "message"

var myError = new MyError("message");
myError instanceof Error; // true
myError.message; // "" !
为什么
newerror(“message”)
设置
message
属性,而
Error.call(this,msg)没有?当然,我可以在
MyError
构造函数中定义
this.message=msg
,但我不太明白为什么一开始还没有设置它

function MyError(msg) {
    var err = Error.call(this, msg);
    err.name = "MyError";
    return err;
}
Error
不会操作
,它会创建一个返回的新错误对象。这就是为什么
Error(“foo”)
在没有
new
关键字的情况下也能正常工作的原因

注意,这是特定于实现的,v8(chrome&node.js)的行为如下

还有
MyError.prototype.\uuuu proto\uuu=Error.prototype是一种不好的做法。使用

MyError.prototype = Object.create(Error.prototype, { 
  constructor: { value: MyError } 
});

A.就像Raynos说的那样,
消息
没有被设置的原因是
错误
是一个返回新错误对象的函数,并且不会以任何方式操作该

B.正确的方法是在
上设置构造函数应用的结果,并以通常复杂的javascripty方式设置原型:

函数MyError(){
var tmp=Error.apply(这个,参数)
tmp.name=this.name='MyError'
this.message=tmp.message
//而不是这个.stack=…,一个更优化的getter
Object.defineProperty(此“堆栈”{
get:function(){
返回tmp.stack
}
})
还这个
}
var IntermediateInheritor=函数(){}
IntermediateInheritor.prototype=Error.prototype
MyError.prototype=新的中间层继承人()
var myError=new myError(“消息”)
console.log(“消息是:“+myError.message+””)//消息是:“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
// 
在这一点上,这种方法唯一的问题是

  • MyError
    中不包括
    stack
    message
    以外的属性,以及
  • stacktrace有一个额外的行,实际上并不需要

第一个问题可以通过使用以下答案中的技巧迭代错误的所有不可枚举属性来解决:,但ie不支持这一点您可以使用error.captureStackTrace筛选堆栈跟踪中不需要的行

function MyError() {
    var tmp = Error.apply(this, arguments);
    tmp.name = this.name = 'MyError';

    this.message = tmp.message;
    /*this.stack = */Object.defineProperty(this, 'stack', { // getter for more optimizy goodness
        get: function() {
            return tmp.stack;
        }
    });

    Error.captureStackTrace(this, MyError); // showing stack trace up to instantiation of Error excluding it.

    return this;
 }
 var IntermediateInheritor = function() {},
     IntermediateInheritor.prototype = Error.prototype;
 MyError.prototype = new IntermediateInheritor();

 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 ...>
函数MyError(){
var tmp=Error.apply(这是参数);
tmp.name=this.name='MyError';
this.message=tmp.message;
/*this.stack=*/Object.defineProperty(this'stack',{//getter以获得更多优化)
get:function(){
返回tmp.stack;
}
});
Error.captureStackTrace(this,MyError);//显示堆栈跟踪,直到错误的实例化为止,不包括它。
归还这个;
}
var IntermediateInheritor=函数(){},
IntermediateInheritor.prototype=Error.prototype;
MyError.prototype=新的中间层继承器();
var myError=新的myError(“消息”);
console.log(“消息是:“+myError.message+””);//消息是:“消息”
console.log(myError instanceof Error);//符合事实的
console.log(myError instanceof myError);//符合事实的
console.log(myError.toString());//MyError:消息
console.log(myError.stack);//MyError:消息\n
// 

在Node.js中,您可以创建如下自定义错误:

var util = require('util');

function MyError(message) {
  this.message = message;
  Error.captureStackTrace(this, MyError);
}

util.inherits(MyError, Error);

MyError.prototype.name = 'MyError';

请参见节点文档中的另一种方法是将新的错误实例作为
this
的原型,这样您就不必知道要复制哪些属性,从而绕过了在答案末尾没有提到的问题

function MyError() {
    if (this === undefined) {
        throw TypeError("MyError must be called as a constructor");
    }
    let newErr = Error.apply(undefined, arguments);
    Object.setPrototypeOf(newErr, MyError.prototype);
    Object.setPrototypeOf(this, newErr);
}
MyError.prototype = Object.create(Error.prototype);

let me = new MyError("A terrible thing happened");
console.log(me instanceof MyError);  // true
console.log(me instanceof Error);  // true
console.log(me.message);  // A terrible thing happened

就我而言,这里更整洁了一点请注意(或
对象.\uuuuu proto\uuuu=
在支持它的非ES6兼容实现上)可能会非常慢,因此如果您在黄金路径上使用这些错误,那么您可能不想这样做。

我非常喜欢制作可重用的.js文件,我几乎在参与的任何项目中都会用到这些文件。当我有时间时,它将成为一个模块

对于我的错误,我创建了一个
exceptions.js
文件,并将其添加到我的文件中

以下是此文件中的代码示例:

const util = require('util');

/**
 * This exception should be used when some phat of code is not implemented.
 * @param {String} message Error message that will be used inside error.
 * @inheritDoc Error
 */
function NotImplementedException(message) {
  this.message = message;
  Error.captureStackTrace(this, NotImplementedException);
}

util.inherits(NotImplementedException, Error);

NotImplementedException.prototype.name = 'NotImplementedException';

module.exports = {
  NotImplementedException,
};
在我的项目的其他文件中,我必须在文件的顶部有这个require行

const Exceptions = require('./exceptions.js');
要使用这个错误,你只需要这个

const err = Exceptions.NotImplementedException(`Request token ${requestToken}: The "${operation}" from "${partner}" does not exist.`);
完整方法实现的示例

const notImplemented = (requestToken, operation, partner) => {
  logger.warn(`Request token ${requestToken}: To "${operation}" received from "${partner}"`);
  return new Promise((resolve, reject) => {
    const err = Exceptions.NotImplementedException(`Request token ${requestToken}: The "${operation}" from "${partner}" does not exist.`);
    logger.error(err.message);
    return reject(err);
  });
};

在ES6中这样做有什么不对

class MyError extends Error {
    constructor(message) {
        super(message);
        // Maintains proper stack trace (only on V8)
        if (Error.captureStackTrace) {
            Error.captureStackTrace(this, MyError);
        }
        this.appcode= 123; // can add custom props
    }
}

感谢您的回答和Object.create继承提示!这并不完全正确。不使用
new
关键字只会导致
Error
构造函数使用
new
关键字递归调用自身,这反过来会使堆栈跟踪从
Error
构造函数内部开始,而不是在您自己初始化调用的代码中开始。因此,总是使用
new
关键字-1来声明某件事是一种不好的做法,而不做任何解释(就我所知,这可能是一件非常愚蠢的事情,但我不知道为什么阅读你的答案)也用于推荐
对象。创建
作为替代方案,但不承认IE 8及以下版本中不支持它。-1用于未正确子类化和
实例不起作用。有关更完整的解决方案,请参见下面的答案“下面的答案”是相对的。2014年6月27日,下面是什么这是(不幸的)正确的做法。被接受的答案并没有将其设置为MyError类型,而只是crea