你会的别人也会,为啥录取你?一样的题怎么把面试官撩到?
深拷贝
面试遇到这个问题,先说一下正常的思路:
- 进行遍历;
- 遍历遇到值类型就赋值;
- 遇到引用类型:判断是Array还是Object,分别新建[]或{},进行递归;
- 返回结果。 这是90%的人都会回答出来的,你的竞争力在哪?
好的面试官会继续问
- 如果出现对象循环引用怎么办?
- 调用栈太多会爆掉,怎么解决?
- 没有亮眼的地方?
下面就解决这些问题:
如果出现对象循环引用怎么办?
使用WeakMap记录所有引用类型的数据。当存在相同引用时,直接用,不再递归,也解决了无限递归问题。
const map = new WeakMap();
if (map.has(origin[key])) {
target[key]= map.get(origin[key]);
} else {
target[key] = new origin[key].constructor();
arr.push({origin: origin[key], target: target[key]});
}
调用栈太多会爆掉,怎么解决?
使用while+数组解决调用栈太长问题。这个方法是非常普遍的,如果面试遇到优化递归的问题,首先考虑while+数组的方法。
解释:遇到对象就push进数组。使用while循环数组,每次取数组的第一项(同时删除这一项),进行遍历操作。当数组为空时,就停止。
const arr = [{origin, target}];
while(tar = arr.shift()) {
...
if (map.has(origin[key])) {
target[key]= map.get(origin[key]);
} else {
target[key] = new origin[key].constructor();
arr.push({origin: origin[key], target: target[key]});
}
...
}
亮眼的地方?
- 使用new origin.constructor() 创建对象。既不用再区分对象和数组,又向面试官展示了你对原型的理解和灵活运用。岂不美哉!!!
- 使用WeakMap记录出现过的对象,体现你对弱引用的理解。
全部代码
const obj = {
a: 1,
b: {
c: {
d: 1
},
},
c: [1, 2, 4]
}
function deepClone(origin, target = {}) {
if (origin === null) return null;
const map = new WeakMap();
const arr = [{origin, target}];
let tar;
while(tar = arr.shift()) {
const {origin, target} = tar;
for (let key in origin) {
if (Object.hasOwnProperty.call(origin, key)) {
if (typeof(origin[key]) === 'object' && origin[key] !== null) {
if (map.has(origin[key])) {
target[key]= map.get(origin[key]);
} else {
target[key] = new origin[key].constructor();
arr.push({origin: origin[key], target: target[key]});
}
} else {
target[key] = origin[key];
}
}
}
}
return target;
}
console.log(deepClone(obj));