当我们想把对象转为JSON串的时候,肯定会想到JSON.stringify;还一种情况,当我们想实现一个深拷贝的时候,也会想到JSON.parse(JSON.stringify());但其实JSON.stringify序列化是有些问题的。先给大家举个例子:
现在有个对象,通过JSON.stringify转一下如下:

转完之后我们发现,函数和值为undefined的属性都丢失了,值为NaN的转为了null ,这就是存在的问题,当我们想实现一个深拷贝的时候,如果对象中没有函数或者undefined或者上面的问题不影响我们的使用,自然是可以通过这种方式的,又方便,谁不愿意用呢。但如果上面的问题有影响到我们正常使用,或者我们就想保留上面的属性,那就不能使用JSON这种方式,可以手写一个深拷贝来实现,可以去看下我之前的一篇博文:《js深拷贝》
出现上面的原因是因为:
- 使用JSON.Stringify 转换的数据中,如果包含 function,undefined,Symbol,这几种类型,不可枚举属性,JSON.Stringify序列化后,这个键值对会消失。
- 转换的数据中包含 NaN,Infinity 值(含-Infinity),JSON序列化后的结果会是null。
- 转换的数据中包含Date对象,JSON.Stringify序列化之后,会变成字符串。
- 转换的数据包含RegExp 引用类型序列化之后会变成空对象。
- 无法序列化不可枚举属性。
- 无法序列化对象的循环引用,(例如: obj[key] = obj)。
- 无法序列化对象的原型链。
JSON.stringify自然好用,但是也要避免上面的问题
针对上面的问题,我想看下能不能解决,然后自己试着写了一下,当然也找了一些关于JSON的方法、参数等资料,重新写了两个方法(算是对stringify和parse方法进行了扩展吧) 如下:
- // JSON.stringify对象序列化,解决undefined、函数和NaN 丢失问题
- function JSONStringify(option) {
- return JSON.stringify(option, (key, val) => {
- // 处理函数丢失问题
- if (typeof val === 'function') {
- return `${val}`;
- }
- // 处理undefined丢失问题
- if (typeof val === 'undefined') {
- return 'undefined';
- }
- // 处理NaN转为null的情况(注意: 这里如果使用isNaN的话,那么对象也会走进去)
- if (val !== val) {
- return `${val}`
- }
- return val;
- }, 2)
- }
- // JSON.parse 反序列化
- function JSONParse(jsonStr) {
- const retain = ['function', 'undefined', 'NaN']
- return JSON.parse(jsonStr, (key, val) => {
- // eval 可能在eslint中报错,需要加入下行注释
- // eslint-disable-next-line
- if (typeof val === 'string' && retain.some(s => val.indexOf(s) >= 0)) {
- return eval(`(function(){return ${val}})()`);
- }
- return val
- })
- }
然后使用这两个方法再试一下
- console.log(JSONStringify(o), 'stringify序列化处理----->>>')
- console.log(JSONParse(JSONStringify(o)), 'parse解析序列化处理----->>>')
打印如下:

开始我以为万事大吉了,但是仔细一看,序列化确实没有问题的,全部保留了,但是解析的时候我的undefined还是没了,undefined和函数、NaN一样处理的,因为一个函数没有返回值的话,默认返回的就是undefined,现在我们让它返回一个undefined,但是没出来呢,也可能是JSON.parse确实转不了undefined,目前还没找到答案,先这样吧,至少比之前好多了。
深拷贝的时候如果不考虑undefined,基本上直接可以用上面的两个方法了,还是蛮方便的,当然手写一个深拷贝的工具方法也方便,看自己喜好吧。
注意:上面两个方法相互结合、相互使用
最后再补充一下,上面有用到eval函数,这是原生js一个函数,可以直接使用,可以参考一位博友的文章:浅谈JS中的 eval函数