前言
最近遇到了一个问题:有时候接口报错了但是仅看返回的 data
和 code
完全看不出问题出在哪。于是想在开发环境中把 err
传回给前端,帮助定位问题。这时问题出现了:前端的 err
字段不管怎么返回都是一个 {}
。
我们知道,我们待传输对象会使用 JSON.stringify()
方法被处理成JSON格式再进行传输的。那问题就比较快的暴露出来了:拿到的空对象猜测是转换的时候被处理成了 {}
。我们可以测试一下:
JSON.stringify(new Error('This is an error'))
// {}
为什么会得到一个空对象?
根据 MDN JSON.stringify() 对该方法描述的最后一条:其他类型的对象,包括 Map/Set/WeakMap/WeakSet
,默认仅会序列化可枚举的属性。可知,Error
类型的对象在进行 JSON.stringify()
方法转换时仅列出可枚举的属性。而我们通过下面代码:
Object.getOwnPropertyDescriptors(new Error('This is an error'))
/*
* 输出:
* message:
* configurable: true
* enumerable: false
* value: "This is an error"
* writable: true
* stack:
* configurable: true
* enumerable: false
* value: "Error: This is an error↵ at <anonymous>:1:34"
* writable: true
*/
可以看出,Error
对象的这两个属性都是不可枚举(enumerable)的,所以这就印证了为啥上面返回给前端的会是一个空对象了。
如何使用 JSON.stringify() “正确”的序列化一个 Error 对象?
其实我们的目的就一个:把 err
的信息返回给前端。那应该用什么办法穿过去呢?有一个最直接的办法就是在后端就先把这个 Error
类型的对象转换为 String
类型,这样就ok了。
MDN 描述中详细介绍了 JSON.stringify() 方法的使用。其中就提到了,该方法其实还有两个参数可以帮助我们更加灵活的选择需要序列化的属性。它的语法是:JSON.stringify(value[, replacer [, space]])
。该方法提供了可选的 replacer
参数,可以让我们选择想要序列化的属性,不论这些属性是否是可枚举的。
JSON.stringify(new Error('This is an error'), ['stack', 'message'])
// "{"stack":"Error: This is an error\n at <anonymous>:1:16","message":"This is an error"}"
由上测试可以得到我们想要的 String
类型的信息了。
当然,有时候我们并不知道某个对象有多少个属性,只是想把它们都打印出来。那我们应该怎么得到这些属性呢?——Object.getOwnPropertyNames()
。该方法返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组。比如:Object.getOwnPropertyNames(new Error('This is an error'))
返回 ["stack", "message"]
。
OS:macOS Catalina 10.15.7
Browser Version: Chrome 87.0.4280.88(正式版本) (x86_64)