使用JSON.stringify字符串化一个Error对象是不可能的吗?

6 浏览
0 Comments

使用JSON.stringify字符串化一个Error对象是不可能的吗?

重现问题

我在尝试使用WebSockets传递错误消息时遇到了一个问题。我可以使用JSON.stringify来满足更广泛的受众来复制我面临的问题:

// node v0.10.15
> var error = new Error('simple error message');
    undefined
> error
    [Error: simple error message]
> Object.getOwnPropertyNames(error);
    [ 'stack', 'arguments', 'type', 'message' ]
> JSON.stringify(error);
    '{}'

问题是我最终得到了一个空对象。

我尝试过的

浏览器

我首先尝试离开node.js并在各种浏览器中运行它。Chrome 28版本给出了相同的结果,有趣的是,至少Firefox尝试过但忽略了这条消息:

>>> JSON.stringify(error); // Firebug, Firefox 23
{"fileName":"debug eval code","lineNumber":1,"stack":"@debug eval code:1\n"}

替换函数

然后我查看了Error.prototype。 它显示原型包含诸如toStringtoSource等方法。 知道函数无法被stringified,当我调用JSON.stringify时,包含一个替换函数以删除所有函数,但后来意识到它也有一些奇怪的行为:

var error = new Error('simple error message');
JSON.stringify(error, function(key, value) {
    console.log(key === ''); // true (?)
    console.log(value === error); // true (?)
});

它似乎不能像通常一样遍历对象,因此我无法检查键是否为函数并忽略它。

问题

是否有办法使用JSON.stringify将原生错误消息字符串化?如果没有,为什么会发生这种行为?

绕过方法

  • 坚持使用基于简单字符串的错误消息,或创建个人错误对象并不要依赖原生错误对象。
  • 提取属性:JSON.stringify({ message: error.message, stack: error.stack })

更新

@Ray Toal建议我查看属性描述符,现在明白为什么它不起作用:

var error = new Error('simple error message');
var propertyNames = Object.getOwnPropertyNames(error);
var descriptor;
for (var property, i = 0, len = propertyNames.length; i < len; ++i) {
    property = propertyNames[i];
    descriptor = Object.getOwnPropertyDescriptor(error, property);
    console.log(property, descriptor);
}

输出:

stack { get: [Function],
  set: [Function],
  enumerable: false,
  configurable: true }
arguments { value: undefined,
  writable: true,
  enumerable: false,
  configurable: true }
type { value: undefined,
  writable: true,
  enumerable: false,
  configurable: true }
message { value: 'simple error message',
  writable: true,
  enumerable: false,
  configurable: true }

键:enumerable: false

接受的答案为此问题提供了解决方法。

admin 更改状态以发布 2023年5月24日
0
0 Comments

您可以定义一个Error.prototype.toJSON来检索代表Error的普通Object

if (!('toJSON' in Error.prototype))
Object.defineProperty(Error.prototype, 'toJSON', {
    value: function () {
        var alt = {};
        Object.getOwnPropertyNames(this).forEach(function (key) {
            alt[key] = this[key];
        }, this);
        return alt;
    },
    configurable: true,
    writable: true
});


var error = new Error('testing');
error.detail = 'foo bar';
console.log(JSON.stringify(error));
// {"message":"testing","detail":"foo bar"}

使用Object.defineProperty()添加toJSON,而不将其作为一个enumerable属性本身。


关于修改Error.prototype,虽然toJSON()可能未针对特定的Error定义,但对于一般的对象,该方法仍然被标准化 (参见步骤3)。因此,发生冲突或冲突的风险很小。

不过,为了完全避免这种情况,可以使用JSON.stringify()replacer参数来代替:

function replaceErrors(key, value) {
    if (value instanceof Error) {
        var error = {};
        Object.getOwnPropertyNames(value).forEach(function (propName) {
            error[propName] = value[propName];
        });
        return error;
    }
    return value;
}
var error = new Error('testing');
error.detail = 'foo bar';
console.log(JSON.stringify(error, replaceErrors));

0
0 Comments

JSON.stringify(err, Object.getOwnPropertyNames(err))

看起来可行

[来自/r/javascript的/u/ub3rgeek的评论] 和 felixfbecker 在下面的评论

0