对象拷贝
Chao 工程师

浅拷贝

1.es3写法

1
2
3
4
5
6
let originObj = {};
let cloneObj = {};

for(const key in originObj) {
cloneObj[key] = originObj[key];
}

2.es5写法

1
2
3
4
5
6
7
8
9
10
// 写法一
Object.getOwnPropertyNames(originObj).forEach(function(key) {
cloneObj[key] = originObj[key]
})

// 写法二
Object.getOwnPropertyNames(originObj).forEach(function (key) {
const des = Object.getOwnPropertyDescriptor(originObj, key);
Object.defineProperty(cloneObj, key, des);
})

3.es6的写法

1
2
3
4
5
6
7
8
9
10
11
12
// 写法一
for(const key of Object.keys(originObj)) {
cloneObj[key] = originObj[key];
}

// 写法二
for (const [key, value] of Object.entries(originObj)) {
cloneObj[key] = value;
}

// 写法三
Object.assign(cloneObj, originObj);

深拷贝

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function deepClone(obj) {
if (typeof obj !== 'object' || obj == null) {
return obj;
}

if(obj instanceof Date) return new Date(obj);
if(obj instanceof RegExp) return new RegExp(obj);

// let newObj = obj instanceof Array ? [] : {}; // 方法一
// let newObj = Array.isArray(obj) ? [] : {}; // 方法二
let newObj = ({}).toString.call(obj) === '[object Array]' ? [] : {}; // 方法三
for (const key in obj) {
if (Object.hasOwnProperty.call(obj, key)) {
newObj[key] = deepClone(obj[key])
}
}
return newObj;
}

WeakMap解决拷贝死循环

上述深拷贝方法有个缺陷,如下:

1
2
3
4
5
let obj1 = {};
let obj2 = {};
obj1.obj2 = obj2;
obj2.obj1 = obj1;
deepClone(obj2);

会循环引用,最后导致栈溢出。

![image-20230317102743971](/Users/xiongchao/Library/Application Support/typora-user-images/image-20230317102743971.png)

WeakMap的key是弱引用类型,如果键名在外部没有被引用了,那么键名和键值会自动被内存回收掉。

WeakMap 就是为了解决这个问题而诞生的,它的键名所引用的对象都是弱引用,即垃圾回收机制不将该引用考虑在内。因此,只要所引用的对象的其他引用都被清除,垃圾回收机制就会释放该对象所占用的内存。也就是说,一旦不再需要,WeakMap 里面的键名对象和所对应的键值对会自动消失,不用手动删除引用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function deepClone(obj, hashMap = new WeakMap()) {
if (typeof obj !== 'object' || obj == null) {
return obj;
}

const hashKey = hashMap.get(obj);
if (hashKey) return hashKey;

let newObj = new obj.constructor();
hashMap.set(obj, newObj)
for (const key in obj) {
if (Object.hasOwnProperty.call(obj, key)) {
newObj[key] = deepClone(obj[key])
}
}
return newObj;
}
1
2
3
4
5
let obj1 = {};
let obj2 = {};
obj1.obj2 = obj2;
obj2.obj1 = obj1;
deepClone(obj2);

![image-20230317102904579](/Users/xiongchao/Library/Application Support/typora-user-images/image-20230317102904579.png)

 Comments