# ❓请分别用深度优先思想和广度优先思想实现一个拷贝函数?
这道题目刚刚好跟我们上面的一道关联性很强,经过上面的深度广度优先遍历我们知道了它们的遍历思想。那么结合这道题目。
假设我们有一个目标对象:
const testTarget = {
name: 'jeff',
tree: {
value: 'root',
children: [
{
value: 'A',
children: [
{ value: 'A-a', children: [{ value: 'A-a-1' }, { value: 'A-a-2' }] },
{ value: 'A-b', children: [{ value: 'A-b-1' }, { value: 'A-b-2' }] },
],
},
{
value: 'B',
children: [
{ value: 'B-a', children: [{ value: 'B-a-1' }, { value: 'B-a-2' }] },
{ value: 'B-b', children: [{ value: 'B-b-1' }, { value: 'B-b-2' }] },
],
},
{
value: 'C',
children: [
{ value: 'C-a', children: [{ value: 'C-a-1' }, { value: 'C-a-2' }] },
{ value: 'C-b', children: [{ value: 'C-b-1' }, { value: 'C-b-2' }] },
],
},
],
},
deepQuote: null,
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
我们的一些辅助函数很有用的哦。
// 辅助函数
const typeMap = {
array: 'Array',
object: 'Object',
function: 'Function',
string: 'String',
null: 'Null',
undefined: 'Undefined',
boolean: 'Boolean',
number: 'Number',
}
const isTypeOf = (obj, type) =>
Object.prototype.toString.call(obj).slice(8, -1) === typeMap[type]
function getEmpty(o) {
// console.log(o); // 可以看到每次循环的值
if (isTypeof(o, 'object')) return {}
if (isTypeof(o, 'array')) return []
if (isTypeof(o, 'function')) {
return new Function(
`"use strict;" return (function() {return ${o.toString()}})`
)
}
if (isTypeof(o, 'regexp')) {
const reFlagReg = /\w*$/
const reg = new RegExp(o.source, reFlagReg.exec(o))
reg.lastIndex = o.lastIndex
return reg
}
return o
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 深度优先思想
// 如果有循环引用的关系,就是环形引用
// testTarget.deepQuote = testTarget;
// 深度优先思想
// 第二个参数解决循环引用
function dfsDeepClone(target, verifyArr = []) {
let result = null
if (isTypeOf(target, 'object')) {
result = {}
for (const key in target) {
if (target.hasOwnProperty(key)) {
const element = target[key]
// console.log(element);
// 验证是否遍历过这个对象
if (verifyArr.includes(element)) {
result[key] = element
} else {
verifyArr.push(element)
// 这里记得把 verifyArr 数组调用时候带入
result[key] = dfsDeepClone(element, verifyArr)
}
}
}
} else if (isTypeOf(target, 'array')) {
result = []
for (let index = 0; index < target.length; index++) {
const element = target[index]
// console.log(element);
// 验证是否遍历过这个对象
if (verifyArr.includes(element)) {
result.push(element)
} else {
verifyArr.push(element)
// 这里记得把 verifyArr 数组调用时候带入
result.push(dfsDeepClone(element, verifyArr))
}
}
} else if (isTypeOf(target, 'function')) {
result = Function(
`"use strict"; return (function() {return ${target.toString()}})`
)
} else {
result = target
}
return result
}
function dfsDeepClone2(target) {
let result = getEmpty(target) // 返回值
let stack = [] // 循环队列
let recordMap = new Map()
function checkCurrent(t, r) {
if (t !== r) {
// 说明是引用类型
stack.push([t, r])
recordMap.set(t, r)
}
}
checkCurrent(target, result)
while (stack.length) {
let [tar, res] = stack.pop()
for (const key in tar) {
let element = tar[key]
// 判断是否是环数据
if (recordMap.has(element)) {
res[key] = recordMap.get(element)
continue
}
// 赋值 getEmpty 里面会返回不是引用类型的值
res[key] = getEmpty(element)
// 判断结果值 推入队列
checkCurrent(element, res[key])
}
}
return result
}
const dfsDeepCloneResult = dfsDeepClone(testTarget)
// 如果把上面的循环引用打开的话,这里会报错
// Converting circular structure to JSON
console.log(JSON.stringify(dfsDeepCloneResult))
// 这里的结果我就不展示了。
// 有兴趣可以去跑一下 https://github.com/lqk9511/blog/blob/master/docs/interview/test/6.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# 广度优先思想
// 广度优先思想
function bfsDeepClone(target) {
let result = getEmpty(target) // 返回值
let queue = [] // 循环队列
let recordMap = new Map() // 记录循环引用变量 解决环数据问题
function checkCurrent(t, r) {
if (t !== r) {
// 说明是引用类型
queue.push([t, r])
recordMap.set(t, r)
}
}
checkCurrent(target, result)
while (queue.length) {
let [tar, res] = queue.shift()
for (const key in tar) {
let element = tar[key]
// 判断环引用
if (recordMap.has(element)) {
res[key] = recordMap.get(element)
continue
}
// 判断目标值
res[key] = getEmpty(element)
// 如果得到结果值跟目标值不一样 添加队列 循环
checkCurrent(element, res[key])
}
}
return result
}
// const bfsDeepCloneResult = bfsDeepClone(testTarget);
// console.log(JSON.stringify(bfsDeepCloneResult));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
也有参考别的大佬的思路啦~在这里
其实解算法题,我觉得重要的还是思考的思路,以及你对其的切入点。还有你的见识啦,读万卷书,搬万顿砖。
思路都在代码里面了,看看注释哦,不行就 debugger
咯,一起进步嘛。
就像我首页的那张图一样 “YOU CAN DO IT!” (好吧,我承认是“贫穷使我们相遇”。)