2015-09-28 117 views
3

在我们的应用程序的NodeJS,我们通过默认的Error对象扩展定义自定义错误类:Object.defineProperty覆盖只读属性

"use strict"; 
const util = require("util"); 

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

util.inherits(CustomError, Error); 

这使我们与堆栈跟踪throw CustomError("Something");显示正确了, instanceof Errorinstanceof CustomError都正常工作。

然而,对于我们的API在返回错误(通过HTTP),我们希望将错误转换成JSON。调用JSON.stringify()上的错误导致"{}",这显然不是真正的消费者描述。

为了解决这个问题,我想重写CustomError.prototype.toJSON(),返回一个对象常量错误的姓名和消息。然后JSON.stringify()只想字符串化该对象和所有将工作伟大:

// after util.inherits call 

CustomError.prototype.toJSON =() => ({ 
    name : "CustomError", 
    message : this.message 
}); 

不过,我很快发现,这将引发TypeError: Cannot assign to read only property 'toJSON' of Error。当我试图写入原型时,这可能是有意义的。所以我改变了构造来代替:

function CustomError(message) { 
    Error.call(this); 
    Error.captureStackTrace(this, CustomError); 
    this.message = message; 
    this.toJSON =() => ({ 
     name : "CustomError", 
     message : this.message 
    }); 
} 

这样(我的预期),则CustomError.toJSON功能将被使用,并且CustomError.prototype.toJSON(从错误)将被忽略。

不幸的是,这只是抛出在对象的构造错误:Cannot assign to read only property 'toJSON' of CustomError

下一个我试图从文件,其中排序在正在抛出了没有错误的问题解决了去除"use strict";,虽然toJSON()功能不使用JSON.stringify()可言。

在这一点上,我只是绝望,只是尝试随机的东西。最后,我结束了使用Object.defineProperty(),而不是直接分配给this.toJSON

function CustomError(message) { 
    Error.call(this); 
    Error.captureStackTrace(this, CustomError); 
    this.message = message; 
    Object.defineProperty(this, "toJSON", { 
     value:() => ({ 
      name : "CustomError", 
      message : this.message 
     }) 
    }); 

这完美的作品。在严格模式下,没有错误被调用,JSON.stringify()返回{"name:" CustomError", "message": "Something"}就像我想要的那样。

所以,虽然它的工作原理,因为我希望它到现在为止,我还是想知道:

  1. 为什么这项工作到底是什么?我期望它是相当于this.toJSON = ...,但显然它不是。
  2. 它应该这样工作吗?即依靠这种行为是否安全?
  3. 如果不是,我应该如何正确覆盖toJSON方法? (如果可能的话)
+1

看看[我的答案在这里](http://stackoverflow.com/questions/22960493/i-dont-understand-writable-and-configurable-property-attributes-of-objects/22960738#22960738)和看看这是你问的问题。谢谢! –

+0

@ Qantas94Heavy这的确很奇怪,但至少可以解释为什么我无法正常分配给属性。我仍然没有从你的评论中的[链接文章](https://esdiscuss.org/topic/set-and-inherited-readonly-data-properties)中获得:Object.defineProperty是否工作(即覆盖无论如何,只读原型属性)通过设计还是我不应该依赖的这种意外行为? – Lapixx

回答

1

因为我注意到你使用箭头函数,我假设你可以访问ES6,也就是说你也可以访问类。

你可以只是简单的扩展Error类。例如:

class CustomError extends Error { 
    toJSON() { 
     return { 
      name: 'CustomError', 
      message: this.message 
     }; 
    } 
} 
+0

好点,看起来更清洁!但是,为什么这个(并使用'Object.defineProperty')工作并试图设置'this.toJSON'不? – Lapixx

+0

实际上我不太确定,不能在节点4.x上重现。 –

1

为什么这项工作到底是什么?

Object.defineProperty只是定义了一个属性(或者如果它的属性已经存在并且是可配置的,它就会改变它的属性)。与转让this.toJSON = …不同,它不关心任何继承,也不检查是否存在可能是setter或non-writable的继承属性。

它应该这样工作吗?即依靠这种行为是否安全?

是的,是的。可能你甚至可以在原型上使用它。


为了您的实际使用情况,鉴于最近的node.js版本,使用ES6类extends Error最好的结果。