使用 JSON.stringify() 列化一个Error

 更新时间:2023年10月02日 15:50:46   作者:Jrainlau  
这篇文章主要介绍了使用 JSON.stringify() 列化一个Error,需要的朋友可以参考下

最近在做 Node 服务端需求的时候,遇到了几次服务端报错的问题。打 log 发现均是一些 Error,但是它们都没法很好地透传给前端浏览器,出现问题只能查看服务端机器的日志,调试起来非常不方便。思考了一下,服务端的内容都是通过 JSON.stringify() 处理,然后设置 Content-type: text/json 的响应头以后再传给前端的,如果 Error 也能够被这样处理,那么调试起来就方便多了。

举个例子

说到 JSON.stringify() 这个方法,相信所有玩过 JS 的同学都不会陌生。它能够方便地把一个对象转化成字符串,在不同的场景中都有着极大的用处。但是它也有一个较大的缺点,无法直接处理诸如 Error 一类的对象。

首先来看个例子:

const err = new Error('This is an error') JSON.stringify(err) // => "{}" 

在控制台运行上述代码后会发现,JSON.stringify() 的结果是一个字符串的 "{}",里面没有任何有效内容。这是否意味着 JSON.stringify() 确实无法处理 Error 呢?下面我们来看看在 MDN 里这个函数是如何定义的。

MDN 定义

首先来看看描述

JSON.stringify()将值转换为相应的JSON格式:

  • 转换值如果有toJSON()方法,该方法定义什么值将被序列化。
  • 非数组对象的属性不能保证以特定的顺序出现在序列化后的字符串中。
  • 布尔值、数字、字符串的包装对象在序列化过程中会自动转换成对应的原始值。
  • undefined、任意的函数以及 symbol 值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成 null(出现在数组中时)。函数、undefined被单独转换时,会返回undefined,如JSON.stringify(function(){}) or JSON.stringify(undefined).
  • 对包含循环引用的对象(对象之间相互引用,形成无限循环)执行此方法,会抛出错误。
  • 所有以 symbol 为属性键的属性都会被完全忽略掉,即便 replacer 参数中强制指定包含了它们。
  • Date日期调用了toJSON()将其转换为了string字符串(同Date.toISOString()),因此会被当做字符串处理。
  • NaN和Infinity格式的数值及null都会被当做null。
  • 其他类型的对象,包括Map/Set/weakMap/weakSet,仅会序列化可枚举的属性。

列了那么多其实是为了凑字数我们只看最后一条描述:

其他类型的对象,包括Map/Set/weakMap/weakSet,仅会序列化可枚举的属性。

“仅会序列化可枚举的属性”,是什么意思呢?众所周知,在 JS 的世界中一切皆对象,对象有着不同的属性,这些属性是否可枚举,我们用 enumerable 来定义。

对象属性的 enumerable

举个例子,我们用 obj = { a: 1, b: 2, c: 3 } 来定义一个对象,然后设置它的 c 属性为“不可枚举”,看看效果会如何:

首先看处理前的效果:

const obj = { a: 1, b: 2, c: 3 } JSON.stringify(obj) // => "{"a":1,"b":2,"c":3}" 

再看处理后的效果:

const obj = { a: 1, b: 2, c: 3 } Object.defineProperty(obj, 'c', { value: 3, enumerable: false }) JSON.stringify(obj) // => "{"a":1,"b":2}" 

可以看到,在对 c 属性设置为不可枚举以后,JSON.stringify() 便不再对其进行序列化。

我们把问题再深入一些,有没有办法能够获取一个对象中包含不可枚举在内的所有属性呢?答案是使用 Object.getOwnPropertyNames() 方法。

依然是刚刚被改装过的 obj 对象,我们来看看它所包含的所有属性:

Object.getOwnPropertyNames(obj) // => ["a", "b", "c"] 

不可枚举的 c 属性也被获取到了!

用同样的方法,我们来看看一个 Error 都包含哪些属性:

const err = new Error('This is an error') Object.getOwnPropertyNames(err) // => ["stack", "message"] 

可以看到,Error 包含了 stackmessage 两个属性,它们均可以使用点运算符 .err 实例里面拿到。

既然我们已经能够获取 Error 实例的不可枚举属性及其内容,那么距离使用 JSON.stringify() 序列化 Error 也已经不远了!

JSON.stringify() 的第二个参数

JSON.stringify() 可以接收三个参数:

语法

JSON.stringify(value[, replacer [, space]])

value

将要序列化成 一个JSON 字符串的值。

replacer 可选

如果该参数是一个函数,则在序列化过程中,被序列化的值的每个属性都会经过该函数的转换和处理;如果该参数是一个数组,则只有包含在这个数组中的属性名才会被序列化到最终的 JSON 字符串中;如果该参数为null或者未提供,则对象所有的属性都会被序列化。

space 可选

指定缩进用的空白字符串,用于美化输出(pretty-print);如果参数是个数字,它代表有多少的空格;上限为10。该值若小于1,则意味着没有空格;如果该参数为字符串(字符串的前十个字母),该字符串将被作为空格;如果该参数没有提供(或者为null)将没有空格。 返回值 节 一个表示给定值的JSON字符串。

我们来看 replacer 的用法:

……如果该参数是一个数组,则只有包含在这个数组中的属性名才会被序列化到最终的 JSON 字符串中……

依然使用上文的 obj 为例子:

const obj = { a: 1, b: 2, c: 3 } Object.defineProperty(obj, 'c', { value: 3, enumerable: false }) JSON.stringify(obj, ['a', 'c']) // => "{"a":1,"c":3}" 

可以看到,我们在 replacer 中指定了要序列化 ac 属性,输出结果也是只有这两个属性的值,且不可枚举的 c 属性也被序列化了!守得云开见月明,Error 对象被序列化的方法也就出来了:

const err = new Error('This is an error') JSON.stringify(err, Object.getOwnPropertyNames(err), 2) // => // "{ // "stack": "Error: This is an error\n at <anonymous>:1:13", // "message": "This is an error" // }" 

后记

文章本来的标题是“你不知道的 JSON.stringify()”,但是总感觉词不达意,有标题党的嫌疑,遂改成更为实在的现标题。

对于一些常用的函数,其背后也有着许多值得探索的内容,比如这次为了让 JSON.stringify() 去序列化一个 Error,我又复习了一遍 JS 对象属性中 enumerable 的相关知识,才知道这些原本以为很底层的基础知识其实对真实业务也有着巨大的作用。夯实基础,永远都是很重要的。

到此这篇关于使用 JSON.stringify() 列化一个Error的文章就介绍到这了,更多相关使用 JSON.stringify() 列化一个Error内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • vue-router路由懒加载及实现方式

    vue-router路由懒加载及实现方式

    这篇文章主要介绍了vue-router路由懒加载及实现方式,路由懒加载的主要作用是将 路由对应的组件打包成一个个的js代码块,只有在这个路由被访问到的时候,才会加载对应组件的代码块,需要的朋友可以参考下
    2022-12-12
  • vue实现一个单文件组件的完整过程记录

    vue实现一个单文件组件的完整过程记录

    整个项目结构清晰,尤其单文件组件的表现力尤为突出,使得每个组件的逻辑都没有过于复杂,所以这篇文章主要给大家介绍了关于vue实现一个单文件组件的相关资料,需要的朋友可以参考下
    2021-06-06
  • VUE中鼠标滚轮使div左右滚动的方法详解

    VUE中鼠标滚轮使div左右滚动的方法详解

    这篇文章主要给大家介绍了关于VUE中鼠标滚轮使div左右滚动的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • Vue+elementui 实现复杂表头和动态增加列的二维表格功能

    Vue+elementui 实现复杂表头和动态增加列的二维表格功能

    这篇文章主要介绍了Vue+elementui 实现复杂表头和动态增加列的二维表格功能,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-09-09
  • vue3使用富文本编辑器Editor.js的简单方法

    vue3使用富文本编辑器Editor.js的简单方法

    Editor.js是一个用于构建具有完全可定制化块结构的现代编辑器的开源库,它提供了一个简洁、可扩展和易于使用的接口,使开发人员能够创建拥有丰富内容和互动性的编辑器,这篇文章主要给大家介绍了关于vue3使用富文本编辑器Editor.js的简单方法,需要的朋友可以参考下
    2024-04-04
  • 基于Vue3自定义实现图片翻转预览功能

    基于Vue3自定义实现图片翻转预览功能

    这篇文章主要为大家详细介绍了如何基于Vue3自定义实现简单的图片翻转预览功能,文中的示例代码讲解详细,具有一定的学习价值,有需要的小伙伴可以参考一下
    2023-10-10
  • Vue 收集表单数据方法详情

    Vue 收集表单数据方法详情

    这篇文章主要介绍了Vue 收集表单数据方法详情,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-05-05
  • Vue结合Element-Plus封装递归组件实现目录示例

    Vue结合Element-Plus封装递归组件实现目录示例

    本文主要介绍了Vue结合Element-Plus封装递归组件实现目录示例,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-04-04
  • vue利用vant组件实现轮播图效果

    vue利用vant组件实现轮播图效果

    vant组件适用于移动端项目,目前项目开源,是市面上做的比较好的开源项目,功能比较强大,本文小编就来为大家介绍一下如何利用vant实现轮播图效果吧
    2023-10-10
  • Electron+Vue实现截屏功能的两种方式

    Electron+Vue实现截屏功能的两种方式

    在Electron环境下,截屏功能相对强大,可以通过desktopCapturer获取应用视频流,实现对整个应用的截屏,而在非Electron环境下,截屏功能受限,只能截取浏览器内容,且存在iframe或base64图片加载问题
    2024-10-10

最新评论