tke*_*ers 5 javascript prototype properties node.js ecmascript-6
在我们的NodeJS应用程序中,我们通过扩展默认的Error对象来定义自定义错误类:
"use strict";
const util = require("util");
function CustomError(message) {
Error.call(this);
Error.captureStackTrace(this, CustomError);
this.message = message;
}
util.inherits(CustomError, Error);
Run Code Online (Sandbox Code Playgroud)
这使我们能够throw CustomError("Something");与堆栈跟踪正确显示出来,并且都instanceof Error和instanceof CustomError正常工作。
但是,为了通过我们的API返回错误(通过HTTP),我们希望将错误转换为JSON。调用JSON.stringify()错误会导致"{}",这显然对消费者而言并不是真正的描述。
为了解决这个问题,我想到了重写CustomError.prototype.toJSON(),以返回带有错误名称和消息的对象文字。JSON.stringify()然后只需将这个对象字符串化,一切都会很好:
// after util.inherits call
CustomError.prototype.toJSON = () => ({
name : "CustomError",
message : this.message
});
Run Code Online (Sandbox Code Playgroud)
但是,我很快就看到这引发了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
});
}
Run Code Online (Sandbox Code Playgroud)
这样(我期望),将使用CustomError.toJSON函数,并且将忽略CustomError.prototype.toJSON(来自Error)。
不幸的是,这只会在对象构造时引发错误: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
})
});
Run Code Online (Sandbox Code Playgroud)
这很完美。在严格模式下,不会调用任何错误,并且会JSON.stringify()返回{"name:" CustomError", "message": "Something"}像我希望的那样。
因此,尽管它现在可以按我的意愿运行,但我仍然想知道:
this.toJSON = ...但显然不是。\n\n\n为什么这确实有效?
\n
Object.defineProperty只是定义一个属性(或者更改其属性,如果它已经存在并且是可配置的)。与赋值不同,this.toJSON = \xe2\x80\xa6它不关心任何继承,也不检查是否存在可能是 setter 或不可写的继承属性。
\n\n\n应该像这样工作吗?即依赖这种行为安全吗?
\n
是的,是的。也许您甚至可以在原型上使用它。
\n\n对于您的实际用例,给定最新的 Node.js 版本,请使用 ES6 类extends Error以获得最佳结果。