如何使用 JSON.stringify() 去序列化一个 Error?

时间: 2019-08-18阅读: 545标签: 错误

最近在做 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 包含了 stack 和 message 两个属性,它们均可以使用点运算符 . 从 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 中指定了要序列化 a 和 c 属性,输出结果也是只有这两个属性的值,且不可枚举的 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 的相关知识,才知道这些原本以为很底层的基础知识其实对真实业务也有着巨大的作用。夯实基础,永远都是很重要的。

原文:https://segmentfault.com/a/1190000020422195

站长推荐

1.阿里云: 本站目前使用的是阿里云主机,安全/可靠/稳定。点击领取2000元代金券、了解最新阿里云产品的各种优惠活动点击进入

2.腾讯云: 提供云服务器、云数据库、云存储、视频与CDN、域名等服务。腾讯云各类产品的最新活动,优惠券领取点击进入

3.广告联盟: 整理了目前主流的广告联盟平台,如果你有流量,可以作为参考选择适合你的平台点击进入

链接: http://www.fly63.com/article/detial/5371

css怎么错误检测?

在写css样式的时候难免会遇到调试后没有效果的情况,原因是你的演示书写有问题,或者是其他的一些因素,下面我们来看一下如何检测css错误。

7个你应该知道的 JavaScript 原生错误类型

从浏览器控制台到运行 Node.js 的终端,我们到处都会看到错误。本文的重点是概述我们在 JS 开发过程中可能遇到的错误类型。良好的错误提示会导致快速而无痛的发展经历与缓慢而痛苦的发展经历之间的区别

JS 中原生错误类型总结

什么?还有除了 200 以外的状态码?不存在的!每次遇到这样的 API,小猪都是黑人问号脸...EXM?王德发?不过那都是另外一个故事了。我们还是说回今天的主题吧,JS 中原生的错误类型。

React 错误边界

部分 UI 中的 JavaScript 错误不应该破坏整个应用程序。 为了解决 React 用户的这个问题,React 16 引入了一个 错误边界(Error Boundaries) 的新概念,错误边界是 React 组件,它可以 在子组件树的任何位置捕获 JavaScript 错误

升级webpack4错误处理

TypeError: Cannot read property vue of undefine。处理:由于vue-loader和webpack4.0未匹配,需要升级vue-loader, npm i vue-loader -D,并且修改配置build/webpack.base.conf.js,加入

npm install时报权限问题的错误

使用管理员的账户进行npm install,一直报权限问题,也参考了网上很多方法,进入C:users删除.npmrc文件,但是我电脑全局搜索根本没找到这个文件,使用npm cache clean --force之后再使用npm install,并没有解决问题

web前端新手最容易出现的4个错误

错误:无论是JavaScript,还是在服务器上运行的代码,开发人员都需要测试并确认它是否可以正常工作,而不是在部署了之后,就认为它应该就能从一而终地运行。

CSS开发中的十大错误用法

自从接触前端软件开发以来,我发现开发猿一直在努力征服着CSS。 理由也很充分,开发人员是用逻辑思考的生物。添加一个DIV元素导致所有代码都不得不往下移一行,而另一个DIV“浮”到左侧,感觉没有任何意义。

javascript如何屏蔽错误?

javascript屏蔽错误的方法:在网页head区域添加window.onerror属性,并将其对应函数返回值设为true即可屏蔽错误。

解决typescript Cannot redeclare block-scoped variable

没有依赖框架来写typescript,纯粹新建一个ts文件,使用tsc编译成js后,ts文件里的声明的变量、函数名都会报错:其实我们写的ts代码是没有问题的,只是ts会对我们声明的变量、具名函数、class都放在了全局作用域

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!

文章投稿关于web前端网站点搜索站长推荐网站地图站长QQ:522607023

小程序专栏: 土味情话心理测试脑筋急转弯幽默笑话段子句子语录成语大全运营推广