继承自Error对象 - message属性在哪里?

Phi*_*ier 32 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 MyError("message");
myError instanceof Error; // true
myError.message; // "" !
Run Code Online (Sandbox Code Playgroud)

为什么new Error("message")设置message属性,而Error.call(this, msg);不是?当然,我可以this.message = msgMyError构造函数中定义,但我不太明白为什么它还没有设置在第一位.

B T*_*B T 38

A.像,Raynos说,之所以message没有被设置的是Error是返回一个新的Error对象和它的功能操作this以任何方式.

B.正确执行此操作的方法是从构造函数设置apply的结果this,以及以通常复杂的javascripty方式设置原型:

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

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

    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 ...>
Run Code Online (Sandbox Code Playgroud)

这种方式在这一点上做的唯一问题(我已经稍微改了一下)就是这样

  • 除了stackmessage不包括的属性MyError,和
  • stacktrace有一个额外的行,这不是必需的.

第一个问题可以通过使用此答案中的技巧迭代错误的所有非可枚举属性来修复:是否可以获取对象的不可枚举的继承属性名称?,但<9不支持.第二个问题可以通过撕掉堆栈跟踪中的那条线来解决,但我不确定如何安全地做到这一点(可能只是删除了第二行的e.stack.toString()??).

更新

我创建了一个继承库来执行此操作^ https://github.com/fresheneesz/proto

  • 为什么你需要`IntermediateInheritor`? (3认同)
  • 这是(遗憾的)正确的做法.接受的答案不会将其设置为MyError类型,而只是创建一个类型Error.因此无法进行自定义错误处理. (2认同)
  • 您也可以使用`Object.create`代替`function x(){}`,然后使用`x.prototype = Error.prototype`,然后使用`new x()` (2认同)
  • 我糊涂了.如果`Error`不操作`this`,你为什么要`Error.apply(this,arguments)`而不是`Error.apply(null,arguments)`? (2认同)
  • 而且我也不认为返回"这个"是必要的. (2认同)
  • 您需要某种方法来向新的 Error 类型添加方法,而无需修改原始的 Error 类型。中间继承者是您要附加新方法的原型。您也许可以仅实例化一个 Error 对象并向该对象添加方法,然后将其用作 MyError 的原型。我不再记得这个的复杂性了,因为这些天我只是使用 proto 来做 javascript 继承。 (2认同)

Ray*_*nos 16

function MyError(msg) {
    var err = Error.call(this, msg);
    err.name = "MyError";
    return err;
}
Run Code Online (Sandbox Code Playgroud)

Error如果不操作this,它会创建一个返回的新错误对象.这就是为什么Error("foo")没有new关键字的原因.

请注意,这是特定于实现的,v8(chrome&node.js)的行为与此类似.

也是MyError.prototype.__proto__ = Error.prototype;一种不好的做法.使用

MyError.prototype = Object.create(Error.prototype, { 
  constructor: { value: MyError } 
});
Run Code Online (Sandbox Code Playgroud)

  • -1在没有解释的情况下声明一些不好的做法(对我所知的所有事情来说,这可能是一件非常愚蠢的事情,但我不知道为什么要阅读你的答案)以及推荐`Object.create`作为另外没有承认它在IE 8及以下版本中不受支持. (3认同)
  • "下面的回答"是相对的.2014年6月27日的内容如下?:d (3认同)
  • 这不完全正确.不使用`new`关键字只会导致`Error`构造函数以`new`关键字递归调用自身,这反过来使得堆栈跟踪在`Error`构造函数内部开始,而不是在你自己的代码中到位你初始化了这个电话.因此,始终使用`new`关键字. (2认同)
  • -1表示没有正确子类化并且`instanceof`不起作用.有关更完整的解决方案,请参阅下面的答案 (2认同)

Pet*_*hev 9

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

var util = require('util');

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

util.inherits(MyError, Error);

MyError.prototype.name = 'MyError';
Run Code Online (Sandbox Code Playgroud)

请参阅节点文档中的captureStackTrace