JSON.stringify()的几个场景
循环引用
使用JSON.stringify()
时,遇到循环引用的时候,会抛出错误TypeError: Converting circular structure to JSON
,如果需要强行转成字符串的话,需要利用到该方法的第二个参数。
主要思路其实就是将循环引用的部分替换成某个标识,等到解析的时候去替换掉,就可以拿到原来的循环引用的对象。通常是为了在输出json
文件后,依然可以得到原来的循环引用的对象来处理。在此也就是抛砖引玉,不做更多的探讨,下面的实现肯定有遗漏的地方,主要就是记录一下思路。
// 先讲环的部分按照自己的格式存起来,并且记录环指向的对象
const JSONStringify = (obj) => {
const cache = new Map();
// 额外套一层,就是为了防止循环引用的是最外层的对象,无法去记录对应的key值
const newObj = {
entry: obj
};
return JSON.stringify(newObj, (key, value) => {
if(typeof value === 'object' && value !== null) {
if(cache.has(value)) {
return `[[object_${cache.get(value)}]]`;
}
cache.set(value, key);
}
return value;
})
};
// 用来专门解析上面产生的字符串
const JSONParse = (objStr) => {
const parseObj = JSON.parse(objStr);
let cache = {};
const ergodic = (obj) => {
for(const [key, value] of Object.entries(obj)) {
// 匹配到了环的部分就去替换
if(/\[\[object_\w+\]\]/.test(value)) {
const [,circleKey] = value.slice(2, -2).split('_');
obj[key] = cache[circleKey];
}
// 记录所有的对象
if(typeof value === 'object' && value !== null) {
cache[key] = value;
ergodic(value);
}
}
};
ergodic(parseObj);
return parseObj.entry;
};
const obj = {
a: {
b: 1
}
};
obj.a.c = obj;
const objStr = JSONStringify(obj);
// {"entry":{"a":{"b":1,"c":"[[Object_entry]]"}}}
const newObj = JSONParse(objStr);
// { a: { b: 1, c: [Circular *1] } }
大JSON的处理
当 JSON.stringify
所生成的字符串长度超过了一定大小的限制后,会抛出Uncaught RangeError: Invalid string length
错误。
我自己的思路大概有两个,一个是拆开去转化,另一个就是使用数据流的形式去读写,目前用第一种方式也能满足我的场景。正常来说,拆开就可以防止一次的JSON.stringify
占据的内存过大,如果拆开一层还不行,可以试试递归几次应该就满足了。
const bigJSONStringify = (obj) => {
let result = '';
if(Array.isArray(obj)) {
result += '[';
for(let value of obj) {
if(typeof value === 'object' && value !== null) {
result += JSON.stringify(value);
} else {
result += value;
}
result += ','
}
result = result.slice(0, -1) + ']';
} else {
result += '{';
for(const [key, value] of Object.entries(obj)) {
if(typeof value === 'object' && value !== null) {
result += `"${key}": ${JSON.stringify(value)}`;
} else {
// 字符串类型加双引号
result += `"${key}": ${typeof value === 'string' ? `"${value}"` : value}`;
}
result += ','
}
result = result.slice(0, -1) + '}';
}
return result;
};
bigJSONStringify([{ a: 'a', v:2, d: { m: 3}}, 2, { c: 1, d: 3 }])
// [{"a":"a","v":2,"d":{"m":3}},2,{"c":1,"d":3}]
bigJSONStringify({ a: 'a', v:2, d: { m: 3}})
// {"a": "a","v": 2,"d": {"m":3}}
格式化写入到文件中的json
经常发现写入到文件中的json
是挤在一起的,就想着有没有可能在写入的时候就格式化一下,发现JSON.stringify
是提供了的,就是第三个参数,为数字的话,就是缩进的格数,为字符串的话,就是用这个字符串替代缩进,不过都有一个最大值的限制,数字不能大于10
,字符串超过10
的长度就取前10
个字符。
fs.writeFileSync('./test.json', JSON.stringify({ a: 1, b: 2, c: 3 }, null, 4), 'utf-8');
//{
// "a": 1,
// "b": 2,
// "c": 3
//}
fs.writeFileSync('./test.json', JSON.stringify({ a: 1, b: 2, c: 3 }, null, '----'), 'utf-8');
//{
//----"a": 1,
//----"b": 2,
//----"c": 3
//}