深拷贝

一个自己写的不成熟deepClone函数

  • 不能复制 不可枚举属性 (去掉第9行左边的判断可以实现)
  • 不能复制原型的方法
  • 不能复制Set Map Symbol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function deepClone(obj) {
if (!obj) return obj
let clone;
if (typeof obj !== 'object') return obj
//是数组
if (Array.isArray(obj)) clone = []
else clone = {}
for (let key in obj) {
if (obj.hasOwnProperty(key) && (typeof obj[key] === 'object')) {
clone[key] = deepClone(obj[key])
} else {
clone[key] = obj[key]
}
}
return clone
}

看到利用MessageChannel实现深拷贝的神操作

  • 可以完美解决循环引用的问题
  • 不可以复制函数
  • 不可以复制Symbol
  • 不支持拷贝原型上的方法和变量
1
2
3
4
5
6
7
8
9
function deepClone(obj) {
return new Promise(resolve => {
const { port1, port2 } = new MessageChannel()
port1.postMessage(obj)
port2.onmessage = e => {
resolve(e.data)
}
})
}
1
2
3
4
5
6
7
//测试
const obj = { a: "", c: undefined, e: 0, f: [], g: NaN, h: null,I:new Set([1,2]),
J: new Map([['a',1]]) }
obj.b = obj//循环引用
deepClone(obj).then(res=> {
console.log(res);
})

structuredClone

适用范围同 MessageChannel 方法的

1
2
3
function deepClone(obj) {
return structuredClone(obj)
}

loadsh的cloneDeep函数

1
import { cloneDeep } from 'loadsh' 

JSON实现深拷贝

  • 不能解决循环引用
  • NaN被拷贝成null
  • Symbol和undefined没被拷贝
1
let newObj = JSON.parse(JSON.stringify(obj))

最后自己重新手搓一个终极版的deepClone

  • 解决了循环引用 – 利用WeakMap
  • 支持深拷贝Symbol,Set,Map,fn
  • 不支持深拷贝Date,RegExp,
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
function deepClone(obj, hash = new WeakMap()) {
if (!obj) return obj
let clone;

if(hash.has(obj)){
// 如果在的话
return hash.get(obj)
}

if (obj instanceof Set) {
return new Set([...obj]) //缺陷--解构是浅拷贝
} else if (obj instanceof Map) {
return new Map([...obj])
} else if (obj instanceof WeakMap) {
throw 'weakmap类型未作处理'
} else if (typeof obj === 'function') {
//方法不用克隆,直接返回
return obj
} else if (obj instanceof Array) { //obj 是数组
clone = [];
hash.set(obj, clone)
obj.forEach(item => {
clone.push(deepClone(item, hash))
})
} else if (typeof obj !== 'object') { //原始值类型
return obj
}
else { //obj 是Object对象
clone = {};
hash.set(obj, clone)
//键是字符
Object.getOwnPropertyNames(obj).forEach(propNames => {
clone[propNames] = deepClone(obj[propNames],hash)
})
//键是Symbol
Object.getOwnPropertySymbols(obj).forEach(syb => {
clone[Symbol(syb.description)] = deepClone(obj[syb],hash)
})
}
return clone
}

优化手写深度克隆

1
2
3
function deepClone(){

}