// 更精确的判断object函数
function isObject(obj) {
return Object.prototype.toString.call(obj) == '[object Object]'
}
function cloneBFS(obj) {
var target = {}; // target是我们最终得到的对象
var arr = [obj]; // 用来保存对象,以便遍历
const map = new Map();
map.set(obj, target); // 建立对象节点与克隆节点的映射关系
while (arr.length > 0) {
const curObj = arr.shift();
// 遍历对象
Object.keys(curObj).map(key => {
const value = curObj[key];
// 如果是对象,则放入arr数组里面,以下次继续遍历
if (isObject(value)) {
// 如果对象已经存在表中,说明存在循环引用
if (map.has(value)) {
map.set(curObj, value); // 这里看不懂
} else {
// 建立这个属性对象与克隆节点的映射关系
map.set(value, {})
arr.push(value);
}
}
// 赋值
const clone = map.get(curObj); // 拿到这个对象
clone[key] = value;
})
}
return target;
}
var obj = {
name: "muyiy",
book: {
title: "You Don't Know JS",
price: "45",
b: {
name: '小b',
age: 16,
next: {
name: '小二'
}
}
},
a1: undefined,
a2: null,
a3: 123
}
obj.a4 = obj
console.log(cloneBFS(obj))
如上深拷贝算法,`map.set(curObj, value);
// 这里看不懂
有大佬知道吗
这里主要解决循环引用的问题:
即:
怎么解决的呢:Map可以用对象作为键来存储对应的数据,拷贝到这里时obj就是键,但由于在执行
cloneBFS(obj)第一步时,obj就作为键存储过了,所以在遍历到obj.a4(指向obj)时,这个
map.has(value)是为真,就不需要建立新的键值对和深拷贝,不然就会堆栈溢出;然后
const clone = map.get(curObj),通过map去将已存在的对象指针赋给obj.a4