问题
一般我们实现深拷贝都是用递归的方式,但是递归缺点就是容易内存泄漏,因为当 js 对象嵌套很深的层级的时候就容易出问题,那解决这个问题就可以用循环的方式。广度优先遍历很适合做深拷贝,因为它是先遍历完一层的数据后再遍历下一层
实现方法
function isObject(val) {if (Object.prototype.toString.call(val) === '[object Object]') return true;
return false;
}
function isArray(val) {return Array.isArray(val);
}
function isFunction(val){if (Object.prototype.toString.call(val) === '[object Function]') return true;
return false;
}
function deepCopy(jsonObj) {if (!isArray(jsonObj) && !isObject(jsonObj)) return jsonObj;
let copy = {};
let queue = [];
let visited = {};
queue.push({
key: 'root',
value: jsonObj,
parent: copy // 根节点 parent 就是 copy
});
while (queue.length != 0) {const first = queue.shift();
const parent = first.parent;
if(visited[first.key] === first.value)continue;// 如果已将访问过则不处理
if ((isArray(first.value) || isObject(first.value))) {for (let [key, value] of Object.entries(first.value)) {if (isArray(value) || isObject(value)) {
let childParent;
if (isObject(value)) {childParent = {};
}
else if (isArray(value)) {childParent = [];
}
queue.push({
key: key,
value: value,
parent: childParent // 重新声明一个 parent
});
parent[key] = childParent;// 连接新的 parent 和旧的 parent
}
else {
queue.push({
key: key,
value: value,
parent: parent
});
}
}
} else {parent[first.key] = first.value;
}
visited[first.key] = first.value;
}
return copy;
}
测试
let obj1 = {
e: 2,
a:{b:44}
}
// 模拟循环引用,并没有爆栈哦
obj1.o = {m:obj1};
const obj2 = deepCopy(obj1);
obj1.a.b = 100;
console.log(obj2.a.b)// 打印 44, 说明 obj1 的改变没有影响 obj2,