寫在前面
此係列來源於開源項目:前端 100 問:能搞懂 80%的請把簡歷給我
爲了備戰 2021 春招
每天一題,督促自己
從多方面多角度總結答案,豐富知識
請分別用深度優先思想和廣度優先思想實現一個拷貝函數?
正文回答
只深拷貝了 Object, Array,其他的非基本類型都是淺拷貝(如果處理 Set 什麼的就太複雜了,題目用意應該是考察遍歷樹和重複引用吧)
DFS 用常規的遞歸問題不大,需要注意下重複引用的問題,不用遞歸的話就用棧
BFS 就用隊列,整體代碼倒是差不多
// 如果是對象/數組,返回一個空的對象/數組,
// 都不是的話直接返回原對象
// 判斷返回的對象和原有對象是否相同就可以知道是否需要繼續深拷貝
// 處理其他的數據類型的話就在這裏加判斷
function getEmpty(o) {
if (Object.prototype.toString.call(o) === "[object Object]") {
return {};
}
if (Object.prototype.toString.call(o) === "[object Array]") {
return [];
}
return o;
}
function deepCopyBFS(origin) {
let queue = [];
let map = new Map(); // 記錄出現過的對象,用於處理環
let target = getEmpty(origin);
if (target !== origin) {
queue.push([origin, target]);
map.set(origin, target);
}
while (queue.length) {
let [ori, tar] = queue.shift();
for (let key in ori) {
// 處理環狀
if (map.get(ori[key])) {
tar[key] = map.get(ori[key]);
continue;
}
tar[key] = getEmpty(ori[key]);
if (tar[key] !== ori[key]) {
queue.push([ori[key], tar[key]]);
map.set(ori[key], tar[key]);
}
}
}
return target;
}
function deepCopyDFS(origin) {
let stack = [];
let map = new Map(); // 記錄出現過的對象,用於處理環
let target = getEmpty(origin);
if (target !== origin) {
stack.push([origin, target]);
map.set(origin, target);
}
while (stack.length) {
let [ori, tar] = stack.pop();
for (let key in ori) {
// 處理環狀
if (map.get(ori[key])) {
tar[key] = map.get(ori[key]);
continue;
}
tar[key] = getEmpty(ori[key]);
if (tar[key] !== ori[key]) {
stack.push([ori[key], tar[key]]);
map.set(ori[key], tar[key]);
}
}
}
return target;
}
// test
[deepCopyBFS, deepCopyDFS].forEach((deepCopy) => {
console.log(deepCopy({ a: 1 }));
console.log(deepCopy([1, 2, { a: [3, 4] }]));
console.log(
deepCopy(function () {
return 1;
})
);
console.log(
deepCopy({
x: function () {
return "x";
},
val: 3,
arr: [1, { test: 1 }],
})
);
let circle = {};
circle.child = circle;
console.log(deepCopy(circle));
});