说明
JSON.stringify无法字符串化带循环的对象我计划把循环的地方替换为循环了的对象的路径
如
const obj = { a: 1, b: 2, c: { d: 1} }
obj.repeat = obj;
obj.c.repeat = obj.c;
这个obj是典型的成环对象且在obj.repeat与obj obj.c.repeat与obj.c处循环了
我希望对其进行stringify后变成
{ a: 1, b: 2, c: { d: 1, repeat: ".c"}, repeat: ""}
表达 obj.c.repeat == 'c' // 对象.c
obj.repeat == '' // 也就是对象本身
即循环处会标识出于什么地方重复了代码:
代码
const replaceLoop = ( () => {
let checkedMap, checkPath;
// Map 记录对象内每个值对应的路径
// Path 记录当前遍历到的路径
function checkLoop(obj){
const copyObj = Object.create(Object.getPrototypeOf(obj));
// 保留原型 不过实际上没什么影响
if( checkedMap.has(obj) ){ // 出现环
return checkedMap.get(obj).join('.'); // 返回环路径
} else {
checkedMap.set(obj, [...checkPath]);
// 添加当前值对应路径 使用拷贝来确保不互相影响
// 字符串数组只需要单层拷贝
}
for(const [ key, val ] of Object.entries(obj) ){
if(!val){ copyObj[key] = val; continue;}
// 如果值相当于False 则不太可能成环 undefined不保留
if(typeof(val) === "object"){ // 如果值很可能成环
checkPath.push(key); // 进入 组装路径
copyObj[key] = checkLoop(val); // 进行递归
checkPath.pop(); // 出路径
}else{ // 可能是函数,无法在stringify下保留
// 但我希望保留值,所以加toString
copyObj[key] = val.toString();
}
}
return copyObj;
}
function doReplace(obj){
// 使用额外的函数进行遍历初始化
checkedMap = new Map();
checkPath = [];
return checkLoop(obj);
}
return doReplace; // 使用闭包避免变量污染
})()
至少看起来大致没问题,不过剩下的你们测测看吧