JSON.stringify() 深拷贝丢数据现象|Web

222 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第 7 天,点击查看活动详情

TLDR

JSON.stringify() 传 Map, Set 会有问题,会 返回 {} ,得不到完整的值,可以通过 Arrays 先将数据转换一下再传给 JSON.stringify()

JSON.stringify() 作 深拷贝 有坑,可能会丢数据,需要判断数据类型

实验

有如下 JavaScript 代码

let mySets = new Set();
const jsonStr = ' {\"name\": \"cube\",\"length\": 12}';
const jsonObj = JSON.parse(jsonStr);

mySets.add(jsonObj);
mySets.add('Hello World');

console.log(JSON.stringify(mySets));

输出结果是

{}

很奇怪,mySets 应该是有值为啥通过 JSON.stringify 打印一个空对象呢?是 JSON 的问题还是 set 的问题?

以前用 Array 时 可以打印出内容啊

const jsonStr = ' {\"name\": \"cube\",\"length\": 12}';
const jsonObj = JSON.parse(jsonStr);

let myArrays = new Array();
myArrays.push(jsonObj);
myArrays.push('Hello World');
console.log(JSON.stringify(myArrays));

输出结果如下

[{"name":"cube","length":12},"Hello World"]

那这说明是 JSON.stringfy(set) 输出不了内容,

那如果需要把 set 内容转成 json 怎么办。

上 MDN 瞅瞅吧,看到一个 values 方法,用这个试试

[Set.prototype.values()](<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/values>)

Returns a new iterator object that yields the values for each element in the Set object in insertion order.

console.log(JSON.stringify(mySets.values()));

输出结果依然是是个

{}

再翻翻文档,看到一个示例

for (const item of mySet1) {
  console.log(item);
}
// 1, "some text", { "a": 1, "b": 2 }, { "a": 1, "b": 2 }, 5

再试试

mySets.forEach((value) => {
  console.log(JSON.stringify(value));
});

看下输出,内容是可以打印出来

[{"name":"cube","length":12},"Hello World"]

根据文档可看到 Set.values() 返回的是个 new iterator object

那目前估计是 JSON.stringify() 在传参一个 iterator object 时不能将内容 输出来。

再翻一下 MDN 文档

• Only enumerable own properties are visited. This means [Map](<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map>)[Set](<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set>), etc. will become "{}". You can use the [replacer](<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#the_replacer_parameter>) parameter to serialize them to something more useful. Properties are visited using the same algorithm as [Object.keys()](<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys>), which has a well-defined order and is stable across implementations. For example, JSON.stringify on the same object will always produce the same string, and JSON.parse(JSON.stringify(obj)) would produce an object with the same key ordering as the original (assuming the object is completely JSON-serializable).

原来只有 可枚举属性 才能被访问到,那如果想通过 JSON.stringify() 得到 Set 的值,那只能把 Set 进行转换了


const jsonStr = ' {\"name\": \"cube\",\"length\": 12}';
const jsonObj = JSON.parse(jsonStr);

let mySets = new Set();
mySets.add(jsonObj);
mySets.add('Hello World');

console.log(JSON.stringify(Array.from(mySets)));

输出内容

[{"name":"cube","length":12},"Hello World"]

结论

见最上 TLDR

参考

MDN Set developer.mozilla.org/en-US/docs/…